2012-02-26 9 views
6

estoy trabajando a través de SICP - un ejercicio es implementar foreach (doseq). Este es un ejercicio académico. En clojure, esto es lo que ocurrió:implementando foreach (doseq) en clojure

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

pero, yo soy un poco turbia sobre si do está engañando, porque do es una forma especial en clojure y no creo que nada de eso tiene sido introducido aún en el SICP. ¿hay una respuesta más minimalista?

Aquí hay otro intento que sólo ejecuta proc en el último elemento:

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

Estás bien. SICP está siendo truculento aquí. Ver el texto muy pequeño de la nota al pie 3 en: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-20.html#call_footnote_Temp_323. Cada vez que haces un 'cond 'en SICP, tienes un' begin' implícito en juego para cada cláusula del 'cond'. Y 'begin' en SICP es bastante' do' en Clojure. – dyoo

Respuesta

3

Uso doseq y ya está todo listo. Por ejemplo:

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

imprimirá:

1 
2 
3 
nil 

EDIT:

Si desea implementar for-each a mano y usando el menor número de formas especiales como sea posible, aquí hay otra alternativa, aunque termina siendo casi tan corto como el tuyo:

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

Curiosamente, el mismo procedimiento podría haber sido escrito de forma más sucinta en el esquema, el dialecto de Lisp utilizado en SICP:

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

sí, quiero implementar eso con la menor cantidad de formularios especiales posible. –

+0

@DustinGetz Actualicé mi respuesta con otra opción, pero en realidad es tan corta como puede ser –

+1

Y no, al menos en Clojure no se puede evitar 'do' para indicar que es necesario ejecutar más de una instrucción en secuencia –

1

Aquí está mi intento. Solo lleva la ejecución de funciones en un bucle 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

eso es bastante ingenioso: explota el hecho de que la parte entre corchetes de un bucle es una lista de enlaces ejecutados en orden. ahora que lo entiendo, esto es una complejidad equivalente al enfoque 'do '. –

+0

Me alegra que lo haya encontrado útil. Pensé una vez más y decidí 'acción nil' estaría bien. – 4e6