今天我们在代码中偶然发现了一个问题,无法回答这个 Clojure 问题:
Clojure 是严格还是惰性地评估不纯代码(或对 Java 代码的调用)?
似乎副作用+惰性序列会导致奇怪的行为。
以下是我们所知道的导致这个问题的信息:
Clojure 有惰性序列:
user=> (take 5 (range)) ; (range) returns an infinite list
(0 1 2 3 4)
而且Clojure有副作用,功能不纯:
user=> (def value (println 5))
5 ; 5 is printed out to screen
user=> value
nil ; 'value' is assigned nil
此外,Clojure 可以调用 Java 对象,这可能会产生副作用。
然而,副作用可能与惰性评估相互作用不佳:
user=> (def my-seq (map #(do (println %) %) (range)))
#'user/my-seq
user=> (take 5 my-seq)
(0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
0 1 2 3 4)
所以它返回了前 5 个元素,但打印了前 31 个!
我假设如果在 Java 对象上调用副作用方法,也可能会出现同样类型的问题。这可能会让推理代码和弄清楚将会发生什么变得非常困难。
附属问题:
-
程序员是否应该警惕并防止这种情况发生? (Yes?)
-
除了序列之外,Clojure 是否执行严格的评估? (Yes?)
Clojure 的惰性 seqs 块大约有 30 个项目,因此进一步减少了少量开销。这不是纯粹主义者的选择,而是一种实用的选择。请参阅“The Joy of Clojure”,了解一次实现一个元素的普通解决方案。
由于您遇到的原因,惰性序列并不是不纯函数的完美匹配。
Clojure 也会严格评估,但对于宏,情况有点不同。内置函数如if
自然会持有评价。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)