Comment puis-je mettre une fonction paresseuse « réduire la carte »?
Question
Je suis en train de mettre en œuvre une fonction « réduction de la carte ». Autrement dit, il doit renvoyer une séquence constituée du résultat de l'application f
pour les 2 premiers éléments de coll
, suivi par le résultat de l'application f
à ce résultat et le troisième élément dans 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)))))
Par exemple, appeler cette fonction comme ceci:
(reduce-map sum-vector c)
devrait revenir:
[[1 0 0 0] [1 1 0 0] [1 1 1 0] [1 1 1 1]]
(En fait, il devrait revenir probablement le premier élément non modifié et, pour mieux schématiser map
, mais je peux corriger plus tard.)
Bon, maintenant, voici ce qu'elle retourne:
((1 1 1 1) (1 1 1 0) (1 1 0 0) (1 0 0 0))
Comment puis-je "pousser" à la fin d'un (ny) suivants?
Si je reduce-map
de remplacement pour recur
, voici ce qu'elle retourne:
(((1 1 1 1) ((1 1 1 0) ((1 1 0 0) ((1 0 0 0))))))
Quelle est la différence entre recur
et vrai récursion dans mon code ci-dessus?
est-il intégré, ou mieux, ou plus idiomatiques, le mode de mise en œuvre reduce-map
?
Enfin, je voudrais la séquence de sortie pour être paresseux. Est-ce que je viens envelopper le tout dans lazy-seq
?
La solution
Cela sonne un peu comme reductions
.
Quant à « pousser » à la fin de suivants: en seqs généraux ne sont pas une « fin », cf. (iterate inc 0)
.
Quant à « pousser » à la fin d'une liste: les listes ne sont pas conçus pour cela. Utilisez un vecteur. Semences votre accumulateur avec []
, non nil
.
Quant à lazy-seq
: Utilisez récursion "true" au lieu de recur
. Voici un exemple:
(defn integer-seq
[start]
(lazy-seq
(cons start (integer-seq (inc start)))))