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は今のままシンブルに残しておくって考えもあるな。