问题描述
Clojure评估不纯的代码(或调用Java)
似乎副作用+延迟序列可能导致奇怪的行为。
这是我们知道的导致这个问题:
Clojure有延迟序列:
user => (取5(范围)); (范围)返回无限列表
(0 1 2 3 4)
user => (def value(println 5))
5; 5打印输出到屏幕
user => value
nil; 'value'被赋值nil
此外,Clojure可以调用Java对象,效果。
但是,副作用可能与延迟评估交互不佳:
user => (def my-seq(map#(do(println%)%)(range)))
#'user / my-seq
user => (取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!
我假设如果调用side-effect Java对象的方法。
附带问题:
- 是否由程序员注意并防止此类情况?(是?)
- 除了序列,Clojure是否执行严格的评估?(是?)
Clojure的惰性seqs块大约30项,所以小的开销进一步减少。这不是纯粹主义者的选择,而是实用的选择。请咨询Clojure的欢乐为一个普通的解决方案来实现一个元素在时间。
懒惰seqs不是一个完美的匹配不纯的函数,因为你遇到的原因。
Clojure也会严格评估,但是使用宏有些不同。 如果
会自然保留评估。
We stumbled upon an issue in our code today, and couldn't answer this Clojure question:
Does Clojure evaluate impure code (or calls to Java code) strictly or lazily?
It seems that side-effects + lazy sequences can lead to strange behavior.
Here's what we know that led to the question:
Clojure has lazy sequences:
user=> (take 5 (range)) ; (range) returns an infinite list
(0 1 2 3 4)
And Clojure has side-effects and impure functions:
user=> (def value (println 5))
5 ; 5 is printed out to screen
user=> value
nil ; 'value' is assigned nil
Also, Clojure can make calls to Java objects, which may include side-effects.However, side-effects may interact poorly with lazy evaluation:
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)
So it returned the first 5 elements, but printed the first 31!
I assume the same kinds of problems could occur if calling side-effecting methods on Java objects. This could make it really hard to reason about code and figure out what's going to happen.
Ancillary questions:
- Is it up to the programmer to watch out for and prevent such situations? (Yes?)
- Besides sequences, does Clojure perform strict evaluation? (Yes?)
Clojure's lazy seqs chunk about 30 items so the little overhead is further reduced. It's not the purist's choice but a practical one. Consult "The Joy of Clojure" for an ordinary solution to realize one element at time.
Lazy seqs aren't a perfect match for impure functions for the reason you encountered.
Clojure will also evaluate strictly, but with macros things are a bit different. Builtins such as if
will naturally hold evaluating.
这篇关于Clojure的懒惰如何与Java / impure代码的调用交互?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!