¿Cómo implementar una función perezosa “reducir mapa”?
Pregunta
Estoy tratando de implementar una función de "reducir mapa". Es decir, se debe devolver una secuencia que consiste en el resultado de aplicar f
a los 2 primeros elementos de coll
, seguido por el resultado de aplicar f
a ese resultado y el tercer elemento de coll
, etc.
(def c [[0 0 0 0] [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]])
(defn- sum-vector [v1 v2]
(map + v1 v2))
(defn reduce-map [f coll & acc]
(if (< (count coll) 2)
(if (empty? acc) coll acc)
(let [head (apply f (take 2 coll))
tail (drop 2 coll)]
(recur f (conj tail head) (conj acc head)))))
Por ejemplo, llamar a esta función como esta:
(reduce-map sum-vector c)
debería volver:
[[1 0 0 0] [1 1 0 0] [1 1 1 0] [1 1 1 1]]
(En realidad, probablemente debería devolver el primer elemento no modificado, así, a map
imitar mejor, yo la puedo arreglar esto más adelante.)
Bien, ahora, esto es lo que devuelve:
((1 1 1 1) (1 1 1 0) (1 1 0 0) (1 0 0 0))
¿Cómo hacer yo "empuje" al final de un ss (ny)?
Si reduce-map
sustituto de recur
, esto es lo que devuelve:
(((1 1 1 1) ((1 1 1 0) ((1 1 0 0) ((1 0 0 0))))))
¿Cuál es la diferencia entre recur
y verdadero recursividad en mi código de seguridad?
Y, ¿Hay un built-in, o mejor, o más idiomática, forma de implementar reduce-map
?
Por último, me gustaría que la secuencia de salida a la pereza. No acabo de envolver todo el asunto en lazy-seq
?
Solución
Esto suena un poco como reductions
.
En cuanto a "empujar" al final de la SEC: en SEQs generales no tienen un "fin", cf. (iterate inc 0)
.
En cuanto a "empujar" al final de una lista: las listas no están diseñados para eso. Utilizar un vector. Las semillas de su acumulador con []
, no nil
.
En cuanto a lazy-seq
: Uso recursividad "verdadero" en lugar de recur
. Aquí un ejemplo:
(defn integer-seq
[start]
(lazy-seq
(cons start (integer-seq (inc start)))))