Clojureの勉強のために、L-99: Ninety-Nine Lisp Problemsを解いてみる。
徐々に難しくなるらしく、最初のほうは組み込み関数で一発で解けそうなものも多かったが。
P01 (*) Find the last box of a list.
色々やり方はありそうだけど、捻らずやるならこんな感じか。
(list (last xs))
(take 1 (reverse xs))
(list (first (reverse xs)))
(drop (- (count xs) 1) xs)
せっかくなので再帰で書いてみた。まぁこれもよくあるパターンか…。
引数の分配束縛で書き換えてみた。
P02 (*) Find the last but one box of a list.
ワンライナーで書くならこんな感じか。
(reverse (take 2 (reverse xs)))
(drop (- (count xs) 2) xs)
(let [ys (reverse xs)] (list (second ys) (first ys)))
letはこのフォーム内のみをスコープにしたローカルな束縛をする時に使うようだ。
reverse xsの結果をysに束縛して、second, first の順で取り出すために使った。
再帰で書くとこんな感じ。P01と代わり映えしないが…。
P03 (*) Find the K'th element of a list.
0オリジンで指定した場所の要素を取り出す関数があるので、それを使えば一発。
(nth xs (dec n))
(dec n)(- n 1)と同じ。
これもnthを使わず再帰で書くとこんな感じ。
条件分岐が複数に渡るので、ifではなくcondを使ってみた。
こちらも引数の分配束縛で書き換えてみた。
P04 (*) Find the number of elements of a list.
こちらもcountを使えば一発だが、使わずに書くとこんな感じか。
(inc n)(+ n 1)と同じ。
fnで無名関数を定義してその場で呼んでいる。
無名関数内で自分自身を再帰的に呼ぶ必要があったので、fと定義した。
ただし、この書き方では末尾再帰最適化が効かないらしく、recurを使ったほうがいいらしい。
さらにfnをシンタックスシュガーで書き換えてみる。
引数は%1, %2 ...で指定し、引数が1つのみの場合は%だけで良い。
recurは末尾再帰の位置以外で呼ぼうとすると
java.lang.UnsupportedOperationException: Can only recur from tail position
が発生するようなので、そういう場合には p04-1.clj のようなスタイルで書く必要がある、ということだろうか。
P05 (*) Reverse a list.
例によってreverseを使えば一発だが、使わずに書いてみる。
p04-3.clj と同じような書き方でやってみた。

Copyright© 2011-2021 Shunsuke Otani All Right Reserved .