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 と同じような書き方でやってみた。