Clojure локальные переменные - PullRequest
1 голос
/ 10 декабря 2011

Я хочу создать функцию (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 Ответ

4 голосов
/ 11 декабря 2011

Если вам требуется изменяемое состояние, используйте один из типов ссылок 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 для динамического определения.

Редактировать: поточно-ориентированная версия, указанная Аланом.

(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))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...