2012-05-11 34 views
15
(take 2 (for [x (range 10) 
       :let [_ (println x)] 
       :when (even? x)] x)) 
>> (* 0 
* 1 
* 2 
* 3 
* 4 
* 5 
* 6 
* 7 
* 8 
* 9 
0 2) 

Tôi cho rằng tôi chỉ đơn giản là dày đặc. Nhưng không, nó chỉ ra rằng Clojure thực sự đánh giá 32 thành phần đầu tiên của bất kỳ trình tự lười biếng nào (nếu có). Ouch.Có phải 'for' không thực sự lười biếng trong clojure?

Tôi đã có một for với cuộc gọi đệ quy trong :let. Tôi đã rất tò mò là tại sao tính toán dường như được tiến hành trong một bề rộng đầu tiên chứ không phải là chiều sâu đầu tiên thời trang. Dường như tính toán (mặc dù, để công bằng, không phải bộ nhớ) đã bùng nổ khi tôi tiếp tục đi xuống tất cả các nhánh trên của cây đệ quy. 32-chunking của Clojure đang đánh giá bề rộng đầu tiên, mặc dù mục đích hợp lý của mã là chiều sâu đầu tiên.

Dù sao, có cách nào đơn giản để buộc 1-chunking hơn 32-chunking của trình tự lười biếng?

Trả lời

13

Michaes Fogus has written a blog entry on disabling this behavior by providing a custom ISeq implementation.

Để ăn cắp trắng trợn từ the modified version by Colin Jones:

(defn seq1 [#^clojure.lang.ISeq s] 
    (reify clojure.lang.ISeq 
    (first [_] (.first s)) 
    (more [_] (seq1 (.more s))) 
    (next [_] (let [sn (.next s)] (and sn (seq1 sn)))) 
    (seq [_] (let [ss (.seq s)] (and ss (seq1 ss)))) 
    (count [_] (.count s)) 
    (cons [_ o] (.cons s o)) 
    (empty [_] (.empty s)) 
    (equiv [_ o] (.equiv s o)))) 

Một cách tiếp cận đơn giản hơn được đưa ra in The Joy of Clojure:

(defn seq1 [s] 
    (lazy-seq 
    (when-let [[x] (seq s)] 
     (cons x (seq1 (rest s)))))) 
+0

Cảm ơn bạn! Điều này đã khiến tôi bối rối trong hai giờ. Tôi không thể tìm ra lý do tại sao (mất 1 (bản đồ một số func [1 2 3 4])) đánh giá một số func cho tất cả 4 yếu tố ... Tôi phải nói, không rõ tại sao điều đó xảy ra, đọc tài liệu trên "bản đồ" và "lấy" –

3

Để trả lời các câu hỏi trong tiêu đề của bạn, không, for là không lười biếng. However, nó:

Mất một vector của cặp một hoặc nhiều ràng buộc dạng/thu-expr, mỗi tiếp theo không hay nhiều bổ, và mang lại một chuỗi lười biếng của các đánh giá của expr.

(tôi nhấn mạnh)

Vì vậy what's going on?

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 chúng, v.v. Nghiêm ngặt nghiêm ngặt trong quần áo lười.

Nói cách khác, forháo hức trả về một lười biếng chuỗi. Mà sẽ không được đánh giá cho đến khi bạn yêu cầu nó, và sẽ được chunked.

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