8

今日、私たちのコードで問題に遭遇し、この 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 は厳密な評価を実行しますか? (はい?)
4

2 に答える 2

8

Clojure のレイジー seq は約 30 個のアイテムをチャンクするため、わずかなオーバーヘッドがさらに削減されます。それは純粋主義者の選択ではなく、実用的なものです。一度に 1 つの要素を実現する通常のソリューションについては、「Clojure の喜び」を参照してください。

レイジー seq は、遭遇した理由により、不純な関数と完全に一致しません。

Clojure も厳密に評価しますが、マクロの場合は少し異なります。などのビルトインifは、当然ながら評価を保持します。

于 2011-10-19T16:18:58.110 に答える
2

遅延構造は、その中で何が参照されているかに関係なく、実装にとって都合のよいときに多かれ少なかれ評価されます。したがって、はい、必要に応じて注意して遅延シーケンスの実現を強制するのはプログラマ次第です。

厳しい評価の意味がわかりません。

于 2011-10-19T17:12:22.120 に答える