Clojure局部变量

时间:2011-12-10 19:59:33

标签: clojure

我想创建一个函数(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是动态范围的。真的吗?有任何词法范围的替代方案吗?谢谢你的帮助。

1 个答案:

答案 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))))