Como implemento uma função preguiçosa do "mapa redutor"?
Pergunta
Estou tentando implementar uma função "mapa redutora". Isto é, deve retornar uma sequência que consiste no resultado da aplicação f
para os 2 primeiros itens de coll
, seguido pelo resultado da aplicação f
para esse resultado e o terceiro item em 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 exemplo, chamando esta função como esta:
(reduce-map sum-vector c)
Deve voltar:
[[1 0 0 0] [1 1 0 0] [1 1 1 0] [1 1 1 1]]
(Na verdade, provavelmente deve devolver o primeiro item não modificado também, para melhorar melhor map
, mas posso consertar isso mais tarde.)
Certo, agora, é isso que ele retorna:
((1 1 1 1) (1 1 1 0) (1 1 0 0) (1 0 0 0))
Como faço para "empurrar" no final de uma seq (NY)?
Se eu substituir reduce-map
por recur
, é isso que ele retorna:
(((1 1 1 1) ((1 1 1 0) ((1 1 0 0) ((1 0 0 0))))))
Qual é a diferença entre recur
E verdadeira recursão no meu código acima?
E, Existe uma maneira interna, ou melhor, ou mais idiomática, de implementar reduce-map
?
Finalmente, eu gostaria que a sequência de saída fosse preguiçosa. Eu apenas envolto a coisa toda em lazy-seq
?
Solução
Isso soa um pouco como reductions
.
Quanto a "empurrar" no final da SEQ: em geral os seqs não têm um "fim", cf. (iterate inc 0)
.
Quanto a "empurrar" no final de uma lista: as listas não foram projetadas para isso. Use um vetor. Semear seu acumulador com []
, não nil
.
Quanto a lazy-seq
: Use recursão "verdadeira" em vez de recur
. Aqui um exemplo:
(defn integer-seq
[start]
(lazy-seq
(cons start (integer-seq (inc start)))))