2012-02-26 18 views
6

sto lavorando attraverso SICP - un esercizio è quello di implementare foreach (doseq). Questo è un esercizio accademico. In clojure, questo è ciò che mi si avvicinò con:implementazione foreach (doseq) in clojure

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

ma, io sono un po 'torbida circa se do è barare, perché do è una forma speciale di clojure e non penso nulla di simile che ha stato introdotto ancora in SICP. c'è una risposta più minimalista?

Ecco un altro tentativo che esegue solo proc sull'ultimo elemento:

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

Stai bene. SICP si sta facendo furbetto qui. Vedere il testo molto piccolo della nota 3 in: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#call_footnote_Temp_323. Ogni volta che esegui un 'cond' in SICP, hai un implicito' begin' in gioco per ogni clausola di 'cond'. E 'begin' in SICP è praticamente' do' in Clojure. – dyoo

risposta

3

Usa doseq ed è tutto pronto. Per esempio:

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

stamperà:

1 
2 
3 
nil 

EDIT:

Se si desidera implementare for-each a mano e utilizzando il minor numero di forme speciali possibili, ecco un'altra alternativa, anche se finisce per essere quasi il più breve del tuo:

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

È interessante notare che la stessa procedura potrebbe essere stata scritta più succintamente in Scheme, il dialetto Lisp utilizzato in SICP:

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

sì, voglio implementarlo con il minor numero di forme speciali possibili. –

+0

@DustinGetz Ho aggiornato la mia risposta con un'altra opzione, ma in realtà è più breve che può ottenere –

+1

E no, almeno in Clojure non si può evitare 'do' per indicare che più di una istruzione deve essere eseguita in sequenza –

1

Ecco il mio tentativo. Porta semplicemente l'esecuzione della funzione in un loop interno.

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

è abbastanza intelligente: sfrutta il fatto che la parte a parentesi di un ciclo è una lista di collegamenti eseguiti in ordine. ora che ho capito, questa è una complessità equivalente all'approccio 'do'. –

+0

Sono contento che tu l'abbia trovato utile. Ho pensato ancora una volta e deciso che "action nil" andrebbe bene. – 4e6

Problemi correlati