2012-02-26 22 views
6

Tôi đang làm việc thông qua SICP - một bài tập là thực hiện foreach (liều lượng). Đây là bài tập học thuật. Trong clojure, đây là những gì tôi đã đưa ra:thực hiện foreach (liều lượng) trong clojure

(defn for-each [proc, items] 
    (if (empty? items) nil 
     (do 
     (proc (first items)) 
     (recur proc (rest items))))) 

nhưng, tôi là một chút u ám về nếu do là lừa dối, bởi vì do là một hình thức đặc biệt trong clojure và tôi không nghĩ rằng bất cứ điều gì như thế có được giới thiệu trong SICP. có câu trả lời tối giản hơn không?

Đây là một nỗ lực mà chỉ thực hiện proc trên yếu tố cuối cùng:

(defn for-each-2 [proc, items] 
    (let [f (first items) 
     r (rest items)] 
    (if (empty? r) 
     (proc f) 
     (recur proc r)))) 
+0

Bạn ổn. SICP là thủ đoạn ở đây. Xem văn bản rất nhỏ của chú thích cuối trang 3 trong: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#call_footnote_Temp_323. Bất cứ khi nào bạn đang thực hiện lệnh 'cond' trong SICP, bạn đã có một' bắt đầu' ngầm định để chơi cho mỗi mệnh đề của 'cond'. Và 'bắt đầu' trong SICP là khá nhiều' do' trong Clojure. – dyoo

Trả lời

3

Sử dụng doseq và bạn đã cài đặt xong. Ví dụ:

(doseq [e '(1 2 3)] 
     (prn e)) 

Sẽ in:

1 
2 
3 
nil 

EDIT:

Nếu bạn muốn thực hiện for-each bằng tay và sử dụng càng ít hình thức đặc biệt càng tốt, đây là một thay thế, mặc dù nó kết thúc gần như ngắn như của bạn:

(defn for-each [f l] 
    (cond (empty? l) nil 
     :else (do (f (first l)) 
        (recur f (rest l))))) 

Điều thú vị là thủ tục tương tự có thể được viết ngắn gọn hơn trong Đề án, phương ngữ Lisp sử dụng trong SICP:

(define (for-each f l) 
    (cond ((null? l) null) 
     (else (f (first l)) 
       (for-each f (rest l))))) 
+0

có, tôi muốn thực hiện điều đó với ít dạng đặc biệt nhất có thể. –

+0

@DustinGetz Tôi đã cập nhật câu trả lời của mình với một tùy chọn khác, nhưng thực sự ngắn gọn như nó có thể nhận được –

+1

Và không, ít nhất trong Clojure bạn không thể tránh 'do' cho biết rằng nhiều hơn một câu lệnh cần được thực thi theo thứ tự –

1

Đây là nỗ lực của tôi. Nó chỉ mang chức năng thực hiện trong một vòng lặp bên trong.

(defn for-each [fun, xs] 
    (loop [fun fun 
     xs xs 
     action nil] 
    (if (first xs) 
     (recur fun (rest xs) (fun (first xs))) 
     xs))) 
+0

thats khá thông minh - nó khai thác một thực tế là phần bracketed của một vòng lặp là một danh sách các bindings thực hiện theo thứ tự. bây giờ tôi hiểu, đây là sự phức tạp tương đương với cách tiếp cận 'do'. –

+0

Tôi rất vui vì bạn thấy nó hữu ích. Tôi nghĩ một lần nữa và quyết định 'hành động nil' sẽ ổn thôi. – 4e6