隣り合う二項の差

どう書く?orgで出題されていた,自分のLisp力でも解けそうな,それでいてLispで書きやすそうなお題をピックアップ


cdr再帰に凝っている自分としては,ループは再帰で書きたい.まさしくcdr再帰(笑)

(defun diff (lis)
  (cond ((> 2 (length lis)) nil)
	(t (cons (- (cadr lis) (car lis)) (diff (cdr lis))))))

(diff '(3 1 4 1 5 9 2 6 5))
(-2 3 -3 4 4 -7 4 -1)

意外にもレスしている人たちはloopとかdo使って処理してた.計算コストを考えたら計数反復ですが.
そしたらすごい人がもっと短いコード書いていた.

(defun diff (lis)
  (mapcar '- (cdr lis) lis))

あれ?なんでmapcarで引数ふたつ取っているんだ??一瞬よくわからなかったけれど,リファレンスを見てようやく思い出した.ふたつ以上のリストを受け取る場合は,一番短いリストに合わせるんだった.だから(cdr lis)の方がひとつ短いので,lisの最後の要素は無視されます.ほーかほーか.


mapcarの使い方については,後述します.

mapcarの使い方

今までmapcarの引数はリストひとつしか使えないと思っていた
リファレンスを見たら,こんな例が

(mapcar 'cons '(1 2 3) '(4 5 6))
((1 . 4) (2 . 5) (3 . 6))

ということは,まさか

(mapcar 'list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))

キタコレ


lambda関数の場合は引数の数だけやってくれるということが予想される

(mapcar '(lambda(x y) (list x y)) '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))

ほい,そのとうり


じゃあ,'consに対して3つ以上のリストが渡されるとエラーになるはず

(mapcar 'cons '(1 2 3) '(4 5 6) '(7 8 9))
引数が多すぎます: (cons 1 4 7)

よしよし,だいぶわかってきたぞ