2024 Clojure 状态调查中分享您的看法!

欢迎!请参阅关于页面了解有关此如何工作的更多信息。

0
语法和读取器

你好,

(def cnt (atom 0))
(defn up[] (swap! cnt #(inc %)))
(defn down[] (swap! cnt #(dec %)))
(defn shift-by[offset] (swap! cnt #(+ % offset)))
(dotimes [_ 10] (up))
(println "cnt up => " @cnt)
(loop [i 0] (if (< i 10) (do (down)(recur (inc i)))))
(println "cnt down => " @cnt)
(def cnt' (for[i (range 5)] (shift-by i)))
(println "cnt shift1 => " @cnt)
(println "cnt' => " cnt')
(println "cnt shift2 => " @cnt)

cnt up => 10
cnt down => 0
cnt shift1 => 0
cnt' => (0 1 3 6 10)
cnt shift2 => 10

为什么shift1 显示 0,而 shift2 显示 10?

此致敬礼,
Daniel

1 答案

0

我的第一反应是'for'的惰性。尝试(def cnt' (vec (for[i (range 5)] (shift-by i))))看看是否改变结果。

是的,这确实会改变结果。

(doall ...) 也行

我觉得我期望使用atom将使惰性表达式强制求值
Sean Corfield by
输出序列(cnt')实现了产生惰性序列。
yadaniel by
>>>>输出序列(cnt')是产生惰性序列的方式。

是的,那么为什么Clojure不等待cnt'评估并输出0呢?
by
因为`for`返回(评估为)一个惰性序列,这意味着它只会在消费时实现单个元素——这只是一个粗略的近似,但大致上是Clojure惰性所在。采用惰性之一的原因就是不需要实现整个(可能是无限的)序列,所以产生惰性序列的操作(如for)可以快速返回。

所以cnt'的值是一个惰性序列。当你打印它时,打印机可以看到它是一个序列,所以它会迭代其元素,这将导致它们被实现,触发代码中实现元素时的副作用。

vec产生一个非惰性向量,因此它需要cnt'中的所有元素,也会导致它们被实现。doall专门用于实现所有元素的目的。

要回答问题“为什么Clojure不等待cnt'评估”——它确实等待着,但正如上面所写的,cnt'评估为惰性序列,这不能保证它的任何元素都已被实现。

我认为惰性效果是一种不良做法
yadaniel by
现在我明白这里发生了什么。

(def cnt (atom 0))
(def cnt' (for[i (range 5)] (shift-by i)))
(println "cnt shift1 => " @cnt)
(println "cnt' => " cnt')
(println "cnt shift2 => " @cnt)

cnt'是惰性的,好的。
第一次打印尝试获取 @cnt,因此惰性序列未经评估
第二次打印针对 cnt',惰性序列被评估,并更新 @cnt
第三次打印仅显示更新的 @cnt

更新 @cnt 是评估的副作用(可能是打印或写入文件)
我认为 Clojure 在这里做得对
...