Gauche:dolist系ループで複数変数
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風味。
- 良い点:括弧が増えない
- 悪い点:(var1 expr1 var2 expr2 ...)形式で多変数を束縛するマクロが他に無いので、一貫性に欠ける。
- 悪い点: Clojureの
(for [x lis1 y lis2] ...)は並列束縛ではなく入れ子なので、混乱するかも。(dolist [x lis1 y lis2] (do-something x y) (do-anothre-thing x y))
案2: 2変数以上は括弧をネストする。(1変数で「も」括弧のネストを許すこともできる)
- 良い点: let族との一貫性。
- 悪い点: 括弧が増える
- 悪い点: 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は今のままシンブルに残しておくって考えもあるな。