Gauche:dolist系ループで複数変数

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風味。

案2: 2変数以上は括弧をネストする。(1変数で「も」括弧のネストを許すこともできる)

どちらの案でも問題になること: 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.generatordo-generatorか。

dolistを拡張したとして、リストしか使えないってのは不便っちゃ不便。 でも任意のシーケンスを許す、とか拡張するならdo-ec使えば、ってことになるし、 それなら中途半端な拡張するよりもdolistは今のままシンブルに残しておくって考えもあるな。

More ...