惰性求值问题

6
我有这样的一段代码。我可以在repl中运行它,但无法从命令行中运行。 我猜测我有一个惰性求值问题。

; 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

致敬。

2个回答

4

一些替代方案:

如果你只想将一堆项目添加到一个由Ref持有的集合中,为每个项目启动一个事务并单独进行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))))

(或者您可以将整个包装在中,不在的主体中使用。)

4

明白了!

解决方案

Clojure没有动机在init-items中运行map函数,因为没有返回结果。我用doall包装它来强制执行,然后就完成了。


3
实际上,在这种情况下,dorun 更适合使用(doall 会保留它所包装的序列的头并返回它,而 dorun 则逐步丢弃它并最终返回 nil -- 因此更适合于有副作用的代码)。 - Michał Marczyk
@Michal:当然,你是完全正确的。我稍微尝试过Clojure,但从未达到高水平,现在,可悲的是,即使那也开始生锈了。感谢你的纠正! - Carl Smotricz
实际上,doseq 更适合处理副作用。dorun 太丑了。 - kotarak
@kotarak:说得好。我一直以为doseq是惰性的,但看了API后发现我错了。 - Carl Smotricz
@Carl:这里有个神奇的提示:doseq。;) 在前面加上"do"通常意味着非懒惰。 - kotarak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接