2012-02-26 70 views
6

我正在通過SICP - 一個練習是實施foreach(doseq)。 這是一個學術練習。 Clojure中,這是我想出了:clojure執行foreach(doseq)

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

但是,我有點陰暗一下如果do被欺騙,因爲do是Clojure中的一種特殊形式,我不認爲這樣的事情有已在SICP中推出。 有更簡約的答案嗎?

這裏的另一種嘗試,只有最後一個元素上執行PROC:

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

你很好。 SICP在這裏很棘手。請參閱http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#call_footnote_Temp_323中腳註3的非常小的文字。無論何時,當你在SICP中做一個'cond'時,你都會在'cond'的每個子句中都有一個隱含的'begin'。在Clojure中,'開始'在SICP中'非常'。 – dyoo 2012-02-27 04:29:34

回答

3

使用doseq和你所有的設置。例如:

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

會打印:

1 
2 
3 
nil 

編輯:

如果你想實現for-each用手使用盡可能少的特殊形式成爲可能,這裏的另一種選擇,雖然它幾乎和你一樣短:

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

有趣的是,同樣的程序可能已在計劃中,SICP使用Lisp的方言編寫得更簡潔:

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

是的,我想用盡可能少的特殊形式來實現它。 – 2012-02-26 19:35:58

+0

@DustinGetz我用另一個選項更新了我的答案,但實際上它的最短時間爲 – 2012-02-26 20:14:11

+1

不,至少在Clojure中,您不能避免用「do」來指示需要按順序執行多個語句 – 2012-02-26 20:15:43

1

這裏是我的嘗試。它只是在內部循環中執行函數執行。

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

這很聰明 - 它利用了一個循環的括起來的部分是按順序執行的綁定列表這一事實。現在我明白了,這與'do'方法相當複雜。 – 2012-02-26 21:00:55

+0

我很高興你覺得它有幫助。我再次想到,並決定'行動無'會很好。 – 4e6 2012-02-26 21:25:26