2012-02-26 14 views
6

pracuję przez SICP - jednym ćwiczeniem jest wdrożenie foreach (doseq). To jest ćwiczenie akademickie. W Clojure, to co wymyśliłem:implementowanie foreach (doseq) w clojure

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

ale jestem trochę mętna o jeśli do oszukuje, bo do jest szczególną formą w Clojure i nie sądzę, że ma coś podobnego wprowadzono jeszcze w SICP. czy jest bardziej minimalistyczna odpowiedź?

Oto kolejna próba który tylko wykonuje proc ostatniego elementu:

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

Masz się dobrze. SICP jest tutaj kuszący. Zobacz bardzo mały tekst przypisu 3 w: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#call_footnote_Temp_323. Za każdym razem, gdy robisz "cond" w SICP, masz implicite "zacząć" w grze dla każdej klauzuli "cond". A "zacząć" w SICP to prawie "robić" w Clojure. – dyoo

Odpowiedz

3

Zastosowanie doseq i gotowe. Na przykład:

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

wypisze:

1 
2 
3 
nil 

EDIT:

Jeśli chcesz realizować for-each ręcznie i przy użyciu jak najmniejszej liczby specjalnych form, jak to możliwe, oto kolejna alternatywa, chociaż kończy się prawie tak krótko, jak twoje:

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

Co ciekawe, ta sama procedura mogła być bardziej zwięźle napisane na schemacie, Lisp dialekt używany w SICP:

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

tak, chcę to zaimplementować przy użyciu jak najmniejszej liczby formularzy specjalnych. –

+0

@DustinGetz Zaktualizowałem swoją odpowiedź inną opcją, ale tak naprawdę to jest tak krótka, jak to może dostać –

+1

I nie, przynajmniej w Clojure nie można uniknąć 'zrobić' dla wskazania, że ​​więcej niż jedna instrukcja musi być wykonana w sekwencji –

1

Oto moja próba. Po prostu wykonuje wykonywanie funkcji w wewnętrznej pętli.

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

To całkiem sprytny - wykorzystuje fakt, że część w nawiasach jest listą powiązań wykonywanych w kolejności. teraz, gdy rozumiem, jest to równoważna złożoność podejścia "do". –

+0

Cieszę się, że okazało się to pomocne. Myślałem raz jeszcze i zdecydowałem, że "akcja zero" będzie w porządku. – 4e6