2010-07-15 3 views
6

У меня такой код. Я могу запустить это в repl, но не могу из командной строки. Наверно, у меня есть ленивая проблема с оценкой.Lazy оценка проблема


; items.clj 

(def items (ref [])) 

(defn init-items [] 
    (map 
    #(dosync 
     (alter items conj %)) 
    ["foo" "bar" "baz" ])) 

(init-items) 
(println (first @items)) 

$ java -jar clojure.jar items.clj 
$ nil 

С уважением.

ответ

4

Получил это!

solution

Clojure не мотивированы, чтобы запустить функцию map в init-items, потому что нет никакого результата не дал. Я завернул это в doall, чтобы заставить исполнение, и престо.

+0

я работал. Большое спасибо. – Osman

+3

На самом деле 'dorun' лучше подходит для этого случая (' doall' держится на голове seq, он обертывает и возвращает его, тогда как 'dorun' отбрасывает его шаг за шагом и, наконец, возвращает' nil' - таким образом, он лучше подходит для побочный эффект). –

+0

@Michal: Конечно, вы абсолютно правы. Я немного потрудился с Clojure, но никогда не достигал высокого мастерства, и теперь, к сожалению, даже это начинает ржаветь. Спасибо за исправление! –

4

Некоторые альтернативы:

Если вы просто хотите добавить кучу предметов в коллекции, состоявшейся в работе, начиная одну транзакцию за единицу и conj ИНГ их отдельно немного расточительно. Вместо этого вы могли бы сделать

(defn init-items [] 
    (dosync (alter items into ["foo" "bar" "baz"]))) 

Если у вас есть какая-то причина, чтобы сделать это в моде одного пункта за шагом, я считаю, что самое идиоматическое и удобный подход будет в настоящее время является использование doseq:

(defn init-items [] 
    (doseq [item ["foo" "bar" "baz"]] 
    (dosync (alter items conj item)))) 

(Или вы могли бы переместить Оберните весь doseq в dosync и не использовать dosync в теле doseq «s.)

Смежные вопросы