8

Chúng tôi đã tình cờ gặp sự cố trong mã của chúng tôi hôm nay và không thể trả lời câu hỏi Clojure này:Sự lười biếng của Clojure tương tác với các cuộc gọi đến mã Java/không tinh khiết như thế nào?

Clojure có đánh giá mã không đúng (hoặc gọi tới Java) không?

Dường như tác dụng phụ + trình tự lười biếng có thể dẫn đến hành vi lạ.


Đây là những gì chúng ta biết rằng dẫn đến câu hỏi:

Clojure có chuỗi lười biếng:

user=> (take 5 (range)) ; (range) returns an infinite list 
(0 1 2 3 4) 

Và Clojure có tác dụng phụ và chức năng bất tịnh:

user=> (def value (println 5)) 
5        ; 5 is printed out to screen 
user=> value 
nil        ; 'value' is assigned nil 

Ngoài ra, Clojure có thể thực hiện các cuộc gọi đến các đối tượng Java, có thể bao gồm các tác dụng phụ. Tuy nhiên, tác dụng phụ có thể tương tác kém với đánh giá lười biếng:

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) 

Vì vậy, nó trả lại 5 yếu tố đầu tiên, nhưng in 31 đầu tiên!

Tôi giả định cùng một loại vấn đề có thể xảy ra nếu gọi các phương thức tác dụng phụ trên các đối tượng Java. Điều này có thể làm cho nó thực sự khó khăn để lý luận về mã và tìm ra những gì sẽ xảy ra.


câu hỏi phụ trợ:

  • là nó lên đến các lập trình viên để xem ra cho và ngăn chặn tình huống như vậy? (Có?)
  • Bên cạnh chuỗi, Clojure có thực hiện đánh giá nghiêm ngặt không? (Có?)

Trả lời

8

Khoảng trống nhỏ của Clojure khoảng 30 mặt hàng nên chi phí nhỏ hơn được giảm thêm. Nó không phải là sự lựa chọn của người theo chủ nghĩa thuần túy mà là sự lựa chọn thực tế. Tham khảo ý kiến ​​"Niềm vui của Clojure" cho một giải pháp thông thường để nhận ra một yếu tố tại thời điểm.

Seq lười biếng không phù hợp hoàn hảo với chức năng không tinh khiết vì lý do bạn gặp phải.

Clojure cũng sẽ đánh giá đúng, nhưng với các macro có một chút khác biệt. Các nội trang dựng sẵn như if sẽ tự nhiên giữ đánh giá.

+2

Đây không phải là cách trộn lẫn các tác dụng phụ và câu hỏi lười biếng - đây là "whoa, thật kỳ lạ, tại sao điều đó lại xảy ra và chúng ta tránh điều đó như thế nào trong tương lai?" câu hỏi. Tôi có đúng trong việc giải thích câu trả lời của bạn là: Clojure đánh giá không tinh khiết/các cuộc gọi Java một cách nghiêm túc, đó là trách nhiệm của lập trình viên, và không pha trộn không tinh khiết với sự lười biếng? –

+3

@MattFenwick, về cơ bản Clojure luôn đánh giá đúng. Lazy seqs về cơ bản sử dụng các thủ thuật tương tự như python với máy phát điện của họ, vv .. Nghiêm ngặt evals trong quần áo lười biếng. :) – progo

2

Cấu trúc lười được đánh giá nhiều hơn hoặc ít hơn bất cứ khi nào thuận tiện cho việc triển khai bất kể nội dung nào được tham chiếu trong chúng. Vì vậy, có, nó lên đến các lập trình viên phải cẩn thận và buộc thực hiện các seqs lười biếng khi cần thiết.

Tôi không biết ý bạn là gì bằng cách đánh giá nghiêm ngặt.

+0

http://en.wikipedia.org/wiki/Strict_evaluation –

+1

Ok, như progo đã nói, clojure đánh giá nghiêm ngặt; * cho các cuộc gọi chức năng và các ràng buộc *. Macro có thể làm bất cứ điều gì họ thích với các đối số của họ. (Lazy) seqs là trừu tượng và đánh giá nghiêm ngặt/háo hức không thực sự áp dụng cho họ trực tiếp; một seq lười biếng đánh giá chính nó - nó chỉ khi bạn cố gắng kiểm tra các yếu tố trong họ rằng bạn chắc chắn những giá trị đó được nhận ra (mặc dù nó có thể đã xảy ra trước đó). –

Các vấn đề liên quan