我们今天在我们的代码中偶然发现了一个问题,无法回答这个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对象上调用副作用方法时可能会出现同样的问题。这可能使得很难推断出代码并弄清楚会发生什么。
辅助问题:
答案 0 :(得分:8)
Clojure的懒人seqs大约有30个项目,因此进一步减少了开销。这不是纯粹主义者的选择,而是实用的选择。请参阅“Clojure的喜悦”,了解实现一个元素的普通解决方案。
由于您遇到的原因,懒惰的seqs不能完美匹配不纯函数。
Clojure也会严格评估,但对于宏,事情会有所不同。像if
这样的内置组件自然会进行评估。
答案 1 :(得分:2)
无论何时引用它们,只要方便实现,就会对orzy构造进行或多或少的评估。所以,是的,这取决于程序员要小心并在需要时强制实现懒惰的seq。
我不知道严格评估的意思。