ANSI Common Lisp 3章 「リスト」

チマチマと練習問題をやってみた.

2. もとのリストでの要素の並びを保持するように動作するunion

(defun new-union (lst oth)
  (if (null lst)
      oth
      (funcall #'(lambda ()
                         (dolist (elt lst)
                                 (setf oth (remove elt oth)))
                         (append lst oth)))))
                         
> (union '(a b c) '(b a d))
(C B A D)
> (new-union '(a b c) '(b a d))
(A B C D)

きもい.lambdaの中がきもい.なんか手続きっぽい.

3. 1つのリストを引数として,各々の要素が出現する回数を返す関数

ちなみに,出現する回数でsortしなければならない.

(defun occurrences (lst)
  (sort (counter '() lst) #'> :key #'cdr)) 

(defun counter (alist lst)
  (if (null lst)
      alist
    (let ((elt (car lst)))
      (counter (append-alist alist (count elt lst) elt) (remove elt lst)))))

(defun append-alist (alist num elt)
  (append alist (list (cons elt num) )))
  
> (occurrences '(a b c d a a c c c d b))
((C . 4) (A . 3) (B . 2) (D . 2))
> (occurrences '(a b c d a a c c c d b d a a))
((A . 5) (C . 4) (D . 3) (B . 2))

最後のsortする部分がどうもわかんなかったので,P.Graham 著 ANSI Common LISP 練習問題解答を参考にした.しかもeqlで比較しなければいけないようだけれど,countしてremoveのほうが楽そうだったのでこんなアプローチ.

5. 各々の要素にその位置を示す数を加えて返す

再帰,反復,mapcarを用いて示す.

;; recursive
(defun pos+a (lst)
  (inner-a 0 lst))

(defun inner-a (pos lst)
  (if (null lst)
      nil
    (cons (+ (car lst) pos) (inner-a (+ pos 1) (cdr lst)))))
      

;; loop
(defun pos+b (lst)
  (do ((pos 0 (+ pos 1)))
      ((null (nth pos lst)) lst)
    (setf (nth pos lst) (+ (nth pos lst) pos))))

;; mapcar
(defun pos+c (lst)
  (let ((i -1))
    (mapcar #'(lambda (x) (+ x (setf i (+ i 1)))) lst)))
    
> (pos+a '(7 5 1 4))
(7 6 3 7)
> (pos+b '(7 5 1 4))
(7 6 3 7)
> (pos+c '(7 5 1 4))
(7 6 3 7)

mapcar版の,lambdaでsetfしてる辺りがえぐいなぁとか思いながらも,参考にしてる解答ではincfマクロを使用しているので,しょうがない感が否めない.rubyなら,mapcar版はこんな感じになるのか.

i = -1
[7, 5, 1, 4].map {|e| e + ( i += 1)}
=> [7, 6, 3, 7]


今日はこれぐらいで.