星田さんの記事に対するコメント。
私はこれから呆れられそうな事を書きます(-_-;)
呆れないから心配すんな(笑)。
っつーかハッキリ言ってやる。「皆が通る道だ」(笑)。
ぶっちゃけた話、reduce/foldlを何故にLispビギナーが敬遠したがるのか。
それはprocの2つの引数と、reduce/foldlの後続する引数(初期値initとそれ以外の引数)の順序が逆だからだ。
これが初期に混乱する原因なの。これ以上の理由はない。
言い換えると、「reduce/foldlでは引数順序が逆になる」って分かれば、使うのに躊躇しなくなる、って事なのね。
例えば、だね。foldl使ってreverseを書いてみる。
(define (my-reverse lst)
(foldl cons '() lst))
これは確かに動くんだけど。
> (my-reverse '(1 2 3 4))
'(4 3 2 1)
>
でもconsと言う2引数関数が想定してる引数順序と、foldlのproc部分以外の引数の順序が逆じゃない?
(cons 'data '(a b c d e ...)) => '(data a b c d e ...)
これがconsの正しい順序なんだけど、my-reverseの定義を見ると逆になってるでしょ?'()にlstの中身がconsされていってる。
そう、だからこう考えないとならない。foldlでは後続する初期値、その他の引数の順序は逆順になるんだ、と。
これをLispビギナーは最初ピンと来ないで、結果混乱して、reduce系の関数を使うのが厭になるんだよ(笑)。
つまり、
(define (shuffle-list lst n)
(foldl (lambda (x y)
(shuffle y)) lst (range n)))
procにあたる (lambda (x y) ...) のyはlstを受け取ってxは(range n)を受け取ってるわけ。
これを、順番通りにxがlstを受け取ってyが(range n)を受け取ってる、って解釈すると星田さんみたいに混乱しちまうんだわ。
でも心配しない。皆最初はそうやって考えて混乱の坩堝に叩き込まれるんだわ(笑)。
今日から寝る前に「foldl/reduceの引数はprocの引数と逆順」と3回唱えるようにしよう(笑)。一週間くらい唱えれば飽きるし、その頃にはそれが身に沁みて分かるようになってる(笑)。
なお、もう一度繰り返すけど、基本的なfoldlの定義は次のようになってる。
(define (my-foldl proc init lst)
(if (null? lst)
init
(my-foldl proc (proc (car lst) init) (cdr lst))))
つまりさ、元々は、my-foldlの定義が次のようだったら混乱は起きなかったのね。
(define (my-foldl proc lst init)
(if (null? lst)
init
(my-foldl proc (cdr lst) (proc (car lst) init))))
こうだったら、procの引数順序と後続する引数順序が一致して、Lispビギナーも混乱しなかった筈なんだよ。
でも、要するにinit(初期値)以降のリストは複数取りたかったから・・・つまり、可変長引数にするため、どうしてもリスト引数はパラメータリストの最後尾にせんとイカンかった、と言う理由があるのね。