2011-11-18 35 views
5

Trong nhiều ngôn ngữ, nếu bạn viết một cái gì đó dọc theo dòng củaClojure có logic mạch ngắn không?

if (foo() || bar() || foobar()) { /* do stuff */ } 

và foo() trả về true, sau đó thanh() và foobar() sẽ không được đánh giá.

Giả sử tôi có mã Clojure sau:

(let [a (simple-function args) 
     b (complex-function args) 
     c (too-lazy-to-optimize-this-function args)] 
    (or a b c)) 

Nếu một đánh giá lại là true, sẽ b và c cũng được đánh giá, hoặc họ sẽ bị bỏ qua?

Cảm ơn!

Trả lời

12

Vì bạn đã trả lời câu hỏi của riêng của bạn, lưu ý rằng mặc dù trong ví dụ của bạn b và c có thể không được đánh giá trong (hoặc abc) cuộc gọi, liên kết cho phép được đánh giá trước đó nên cuộc gọi hàm quá lười để tối ưu hóa-chức năng này được đánh giá. Clojure không phải là lười biếng như vậy.

Để được rõ ràng: để đánh giá điều kiện các cuộc gọi chức năng, bạn cần phải đặt các biểu hiện đánh giá chúng trong or cuộc gọi, về cơ bản:

(or (simple-function args) 
    (complex-function args) 
    (too-lazy-to-optimize-this-function args)) 
+0

Tôi chấp nhận một điều này bởi vì nó thảo luận về Gotcha mà tôi đã không biết. – Joel

+4

Nó không phải là một bản ghi nhớ, thay vì bạn phải hiểu tất cả mọi thứ là háo hức ngoại trừ trình tự lười biếng, và các chức năng mà làm việc trên chúng. Các 'hoặc' ngắn mạch vì nó là một vĩ mô, nó mở rộng để http://bit.ly/u8xnms. Nếu nó là một hàm, nó sẽ đánh giá các đối số của nó. Thay vào đó, macro macro mở rộng thành if, là một dạng đặc biệt và các mạch ngắn. – gtrak

1

Ngay sau khi tôi nhập xong câu hỏi này, tôi nhận ra rằng tôi chỉ có thể xem tài liệu cho 'hoặc'.

Từ các tài liệu: "Ước lượng exprs cùng một lúc, từ trái sang phải Nếu một hình thức trả về một giá trị thực sự hợp lý, hoặc trả về giá trị và không đánh giá bất kỳ các biểu thức khác, nếu không nó. trả về giá trị của biểu thức cuối cùng. (hoặc) trả về số không. "

4

Khi nghi ngờ, tham khảo ý kiến ​​the documentation:

hoặc
vĩ mô
Cách sử dụng:

(or) 
    (or x) 
    (or x & next) 

Ước lượng exprs cùng một lúc, từ trái sang phải. Nếu một biểu mẫu trả về giá trị đúng logic hoặc trả về giá trị đó và không đánh giá bất kỳ biểu thức nào khác, nếu không thì giá trị này sẽ trả về giá trị của biểu thức cuối cùng. (hoặc) trả về nil.

(tôi nhấn mạnh).

Các documentation for and thấy nó cư xử theo cách tương đương quá.

0
if (foo() || bar() || foobar()) { /* do stuff */ } 

để

(if (or (foo) (bar) (boobar)) (comment do stuff)) 

hoặc

(when (or (foo) (bar) (boobar)) (comment do stuff)) 
10

Những câu trả lời khác đều tốt, nhưng khi nghi ngờ, bạn có thể luôn kiểm tra nó trên REPL:

user=> (or true (do (println "hello") true)) 
true 
user=> (or false (do (println "hello") true)) 
hello 
true 
+0

+1 để trình diễn thay vì nêu rõ! – mikera

1

Có, Clojure thực sự có đánh giá ngắn mạch.

Một tính năng thú vị trong Clojure/Lisps khác là nó cũng có thể mở rộng ngôn ngữ với các cấu trúc mới cũng cung cấp đánh giá ngắn mạch. Điều này không thể được thực hiện bằng cách sử dụng các hàm trong hầu hết các ngôn ngữ khác vì tất cả các tham số cho hàm phải được đánh giá trước khi hàm được gọi.

Dưới đây là một ví dụ về một macro để thực hiện một chức năng NAND ngắn mạch trong Clojure:

(defmacro nand 
    ([x] 
    `(not ~x))    ; NAND is equivalent to NOT for one argument 
    ([x & xs] 
    `(let [nand# (not ~x)] 
     (if nand# 
     true    ; short circuit if we can prove the nand is true 
     (nand [email protected]))))) ; continue with the other expressions otherwise 

(nand true true) 
=> false 

(nand false (println "Expression with a side effect!")) 
=> true 
Các vấn đề liên quan