2012-02-26 2 views
6

Я работаю через SICP - одно упражнение - реализовать foreach (доза). Это академическое упражнение. В Clojure, это то, что я придумал:внедрение foreach (доза) в clojure

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

, но я немного мутная о том, если do обман, потому что do является особой формой в Clojure и я не думаю, что что-то подобное есть был введен еще в SICP. есть более минималистский ответ?

Вот еще одна попытка, которая выполняет только прок от последнего элемента:

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

Все в порядке. SICP здесь сложный. См. Очень маленький текст сноски 3 в: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#call_footnote_Temp_323. Каждый раз, когда вы выполняете 'cond' в SICP, у вас есть неявное' begin' в игре для каждого предложения 'cond'. И «начать» в SICP в значительной степени «делать» в Clojure. – dyoo

ответ

3

doseq Используйте и вы все сделали. Например:

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

Напечатает:

1 
2 
3 
nil 

EDIT:

Если вы хотите реализовать for-each вручную и с использованием в качестве несколько специальных форм, как это возможно, вот еще одна альтернатива, хотя он заканчивается почти таким коротким, как ваш:

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

Интересно, что та же самая процедура могла быть написана более сжато на схеме, лисповской диалекта в SICP:

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

Да, я хочу реализовать это с как можно меньшим количеством специальных форм. –

+0

@DustinGetz Я обновил свой ответ с помощью другого варианта, но на самом деле это примерно так же коротко, как он может получить –

+1

И нет, по крайней мере, в Clojure вы не можете избежать 'do' для указания того, что несколько порядков должны выполняться последовательно –

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'. –

+0

Я рад, что вы сочли это полезным. Я снова подумал и решил, что «действие нуль» будет в порядке. – 4e6

Смежные вопросы