Shiro(2012/03/17 15:09:34 UTC): ちょっと思いつき。
dolist
, dotimes
はちょろっと副作用目的のループを書くのに
便利 (for-each
だとループ内処理を先に書かないとならないけど、
意識として先にデータがあって後から処理を書きたい場合も多い)
なんだけど、ひとつの変数でしかループを回せない。たまに複数変数で並列に回したくなる時があって、
for-eachに書き換えるのを面倒だなあと感じてた。
まあ、srfi-42 (x:SRFI-42) のdo-ec
って手もあるんだけど、
do-ec
も微妙に冗長なんだよな。
;; 1変数の場合 (dolist [x lis] (do-something x) (do-another-thing x)) (for-each (^x (do-something x) (do-another-thing x)) lis) (do-ec (: x lis) (begin (do-something x) (do-another-thing x))) ;; 2変数の場合 (for-each (^[x y] (do-something x y) (do-another-thing x y)) lis1 lis2) (do-ec (:parallel (: x lis1) (: y lis2)) (begin (do-something x y) (do-another-thing x y)))
で、dolist
を多変数に拡張できたらいいんじゃないかと。
案1: Clojureのlet風味。
(for [x lis1 y lis2] ...)
は並列束縛ではなく入れ子なので、混乱するかも。
(dolist [x lis1 y lis2] (do-something x y) (do-anothre-thing x y))
案2: 2変数以上は括弧をネストする。(1変数で「も」括弧のネストを許すこともできる)
(dolist [[x lis1] [y lis2]] (do-something x y) (do-anothre-thing x y))
どちらの案でも問題になること: Common Lispとの互換性から、dolistの束縛部分にはオプショナルでdolist自体の戻り値が 書ける。それとの整合性をどうするか。こんな使い方↓
(let1 retval '() (dolist [x lis retval] (push! retval (do-something x)) (do-anothre-thing x)))
まあSchemeではあんまりこういう書き方しないんだけど。
一応、案1なら束縛フォームの要素が奇数個の時に最後の要素をretvalとして扱うという手はあり。 案2の場合はretvalに関数呼び出し式が来ると束縛フォームと区別がつかないので、 2変数の場合はretvalをサポートしないか、別の構文を入れることになる。
考えてみたらdotimesは「0からnまで」のループしかできないから多変数並列で回す意味が無いんだな。
意味があるとすればdolistと、gauche.generator
の
do-generator
か。
dolistを拡張したとして、リストしか使えないってのは不便っちゃ不便。
でも任意のシーケンスを許す、とか拡張するならdo-ec
使えば、ってことになるし、
それなら中途半端な拡張するよりもdolistは今のままシンブルに残しておくって考えもあるな。