mapcanってなによ
なんとなくOn Lispを読み始めた。読む本には不自由していない。向こう数年、することも無いだろう。
さて、3章の終盤で
- 彼らは副作用を使う部分をいくつかの関数に隔離し、プログラムの大部分は純粋に関数型スタイルで書けるようにする。
- 関数が副作用を使うのをさけられないなら、彼らは少なくともそこに関数型のインターフェースを盛り込もうとする。
- 彼らは関数に明確な目的を一つだけ与える。
と出てくるまで、副作用の使用には注意を払うべきであることが書いてあった。だからなのか、4章のall-nicknamesの箇所で出てきたmapcanという関数の使用について、ちょっと悩んだ。前段の刷り込みのおかげで、副作用のあるコードが書いてあると、「何か副作用を使わざるを得ない理由があるのだな...」と先入観を持ってみてしまうようになっていたからかな。
調べてみると、mapcanはschemeでいうとSRFI-1のappend-map!に相当するらしい。これは言い換えると、
(apply append! (map fn list1 list2 list3 ...)
と等価な手続き。append!ってのはSRFI-1の手続きで、appendの副作用バージョン。次のような動作をする。
gosh> (define a (list 1 2 3)) a gosh> (define b (list 4 5 6)) b gosh> (define c (list 'foo 'bar 'baz)) c gosh> (append a b c) (1 2 3 4 5 6 foo bar baz) gosh> a (1 2 3) gosh> b (4 5 6) gosh> c (foo bar baz) gosh> (append! a b c) (1 2 3 4 5 6 foo bar baz) gosh> a (1 2 3 4 5 6 foo bar baz) gosh> b (4 5 6 foo bar baz) gosh> c (foo bar baz)
引数として渡した値に対して破壊的な処理がなされている。実は、append-map!に対して、副作用なしバージョンのappend-mapもあるらしい。こっちは
(apply append (map fn list1 list2 list3 ...))
と等価な手続きらしい。
で、append-map!が有用な局面が想像できないのは置いといて、なぜ、副作用を持つappend-map!に相当するmapcanを使う必要があったのか、ということに関してしばらく悩んだ。実際、ここの例all-nicknamesに限っては、append-mapでもappend-map!でも同じ結果が得られる。
もしかして、理由は単純で、append-mapに相当する関数は無いからなのかな。
http://www.komaba.utmc.or.jp/~flatline/onlispjhtml/
Gauche Users’ Reference: Top