Как лень Clojure взаимодействует с вызовами Java / нечистым кодом?

Сегодня мы наткнулись на проблему в нашем коде и не смогли ответить на этот вопрос 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 строгую оценку помимо последовательностей? (Да?)
8
задан Matt Fenwick 19 October 2011 в 16:16
поделиться