我想创建一个函数(thunk),它将返回列表中的连续元素。做这个的最好方式是什么?我根据对clojure中局部变量如何工作的明显缺陷的理解编写了这段代码:
(defn reader-for [commands]
(with-local-vars
[stream commands]
(fn []
(let
[r (var-get stream)]
(if (empty? r)
nil
(let
[cur (first r)
_ (var-set stream (rest r))]
cur))))))
在这段代码中我得到:
#<CompilerException java.lang.IllegalStateException: Var null/null is unbound. (Chapel.clj:1)>
这似乎表明with-local-vars是动态范围的。真的吗?有任何词法范围的替代方案吗?谢谢你的帮助。
答案 0 :(得分:4)
如果需要可变状态,请使用其中一种clojure引用类型:
user=> (defn reader-for [coll] (let [a (atom coll)] (fn [] (let [x (first @a)] (swap! a next) x)))) #'user/reader-for user=> (def f (reader-for [1 2 3])) #'user/f user=> (f) 1 user=> (f) 2 user=> (f) 3 user=> (f) nil
此外,let
用于词法作用域,binding
用于动态作用域。
编辑:Alan指出的线程安全版本。
(defn reader-for [coll] (let [r (ref coll)] #(dosync (let [x (first @r)] (alter r next) x))))
只是为了好玩,一个带有原子的线程安全版本(不要这样做):
(defn reader-for [coll] (let [a (atom coll)] (fn [] (let [ret (atom nil)] (swap! a (fn [[x & xs]] (compare-and-set! ret nil x) xs)) @ret))))