みどりねこ日記

よくわからないけど、頑張りますよ。

Clojure:binding と遅延シーケンス

Clojure in Action読んでて、へえってなったのでメモ。

当然と言えば当然なのかもしれないけれど。

(def ^:dynamic *factor* 10)

(defn multiply [x]
  (* x *factor*))

(map multiply [1 2 3])

(binding [*factor* 20]
  (map multiply [1 2 3]))

Clojure の var はbindingで束縛することができる。

しかし直感に反して上のどちらのmapも [10 20 30] を返す。

これはなぜかというと、mapのような関数は遅延シーケンスを返すからで、この遅延シーケンスは必要となるまで評価されない。そして評価が実際に行われたときはすでにbindingフォームの外であるので、 factor も元々の10に戻っている。

これを意図したようにするには

(binding [*factor* 20]
  (doall (map multiply [1 2 3])))

とする必要がある。

どうてきすこーぷ、気をつけよう。

なんかこれ同じようなことをDBでもやったような気がする。

DBのコネクションをラップしたマクロが用意されてて、そいつが返すのは遅延シーケンスだということに気づかず、コネクションを閉じる前に結果を現実化しなかったせいでDBから結果が返ってきてないように見えて慌てたような。

Clojure in Action

Clojure in Action