今天我们在代码中偶然发现了一个问题,无法回答这个 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 对象上调用副作用方法,也会出现同样类型的问题。这可能会使推理代码和弄清楚会发生什么变得非常困难。
辅助问题:
- 程序员是否应该注意和防止这种情况?(是的?)
- 除了序列,Clojure 是否执行严格的评估?(是的?)