2012-07-23 28 views
6

Tại sao bit này mã Clojure:Clojure liên tục và chức năng bản đồ

user=> (map (constantly (println "Loop it.")) (range 0 3)) 

Năng suất sản lượng này:

Loop it. 
(nil nil nil) 

tôi mong đợi nó để in "Vòng nó" ba lần như một mặt hiệu quả của việc đánh giá hàm ba lần.

Trả lời

9

constantly không đánh giá đối số của nó nhiều lần. Đó là một hàm, không phải là macro, do đó đối số được đánh giá chính xác một lần trước khi chạy constantly. Tất cả constantly sẽ lấy đối số (được đánh giá) của nó và trả về một hàm trả về giá trị đã cho mỗi khi nó được gọi (không đánh giá lại bất cứ thứ gì kể từ khi tôi nói, đối số được đánh giá trước khi constantly thậm chí chạy).

Nếu tất cả những gì bạn muốn làm là gọi (println "Loop it") cho mọi phần tử trong phạm vi, bạn nên chuyển điều đó vào làm hàm để ánh xạ thay vì constantly. Lưu ý rằng bạn sẽ thực sự phải chuyển nó thành một hàm, không phải là một biểu thức được đánh giá.

+0

Liếc nhìn nguồn. Điều này trông giống như một người chiến thắng. – Mike

+0

Đã cố gắng sử dụng liên tục để tránh một cách rõ ràng đi qua trong một đối số tôi không cần. Tuy nhiên, sẽ giải quyết cho điều này. – Mike

+10

Lưu ý rằng nếu bạn chỉ muốn tác dụng phụ, bạn nên sử dụng 'doseq' hoặc' dotimes'. Vì 'map' là lười, bạn sẽ không nhận được kết quả mong muốn trừ khi bạn ép nó bằng' doall' hoặc 'dorun'. –

3

Bạn có thể nhận được hành vi gần với ý định của mình bằng cách sử dụng số repeatedly và biểu thức lambda.

Ví dụ:

(repeatedly 3 #(println "Loop it")) 

Trừ khi bạn đang ở REPL, điều này cần phải được bao quanh bởi một dorun hoặc tương đương. repeatedly là lười biếng.

+0

Lambda sẽ không biên dịch do nó muốn sử dụng đối số mà tôi chuyển cho nó. Trong trường hợp này, tôi chỉ muốn bỏ qua đối số. – Mike

+0

Tôi đã thêm một ví dụ về việc sử dụng, tương tự như của bạn. – sortega

+0

Ồ, điều đó có ý nghĩa hơn nhiều. Cảm ơn! – Mike

3

Vì sepp2k đúng chỉ ra constantly là một hàm nên đối số của nó sẽ chỉ được đánh giá một lần.

Cách thành ngữ để đạt được những gì bạn đang làm gì ở đây sẽ được sử dụng doseq:

(doseq [i (range 0 3)] 
    (println "Loop it.")) 

Hoặc cách khác dotimes (đó là một chút ngắn gọn hơn và hiệu quả trong trường hợp đặc biệt này là bạn không thực sự sử dụng trình tự sản xuất bởi range):

(dotimes [i 3] 
    (println "Loop it.")) 

Cả hai giải pháp đều là phòng không lười biếng, mà có lẽ là những gì bạn muốn nếu bạn chỉ chạy một số mã cho các tác dụng phụ.

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