Clojure的懒惰如何与调用Java /不纯的代码相互作用?

Mat*_*ick 8 functional-programming clojure lazy-evaluation clojure-java-interop

我们今天在我们的代码中偶然发现了一个问题,并且无法回答这个Clojure问题:

Clojure是严格还是懒惰地评估不纯的代码(或调用Java代码)?

似乎副作用+懒惰序列可能导致奇怪的行为.


以下是我们所知道的问题:

Clojure有懒惰的序列:

user=> (take 5 (range)) ; (range) returns an infinite list
(0 1 2 3 4)
Run Code Online (Sandbox Code Playgroud)

Clojure有副作用和不纯的功能:

user=> (def value (println 5))
5                               ; 5 is printed out to screen
user=> value
nil                             ; 'value' is assigned nil
Run Code Online (Sandbox Code Playgroud)

此外,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)
Run Code Online (Sandbox Code Playgroud)

所以它返回了前5个元素,但是打印了前31个元素!

我假设如果在Java对象上调用副作用方法,可能会出现同样的问题.这可能使得很难推断出代码并弄清楚会发生什么.


辅助问题:

  • 程序员是否需要注意并防止出现这种情况?(是?)
  • 除了序列,Clojure是否会进行严格的评估?(是?)

unp*_*680 8

Clojure的懒人seqs大约有30个项目,因此进一步减少了开销.这不是纯粹主义者的选择,而是实用的选择.请参阅"Clojure的喜悦",了解实现一个元素的普通解决方案.

由于您遇到的原因,懒惰的seqs不能完美匹配不纯函数.

Clojure也会严格评估,但对于宏,事情会有所不同.像内置的那样if自然会进行评估.

  • @MattFenwick,基本上Clojure总是严格评估.懒惰的seqs基本上使用与python相同的技巧与他们的发电机等.懒惰的衣服严重的逃避.:) (3认同)
  • 这不是一个如何混合副作用和懒惰的问题 - 这是一个"哇,这很奇怪,为什么会发生这种情况,我们将来如何避免这种情况?" 题.我是否正确地将您的答案解释为:Clojure严格评估不纯/ Java调用,这是程序员的责任,并且不要混淆不洁与懒惰? (2认同)