隣り合う二項の差
どう書く?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)
よしよし,だいぶわかってきたぞ