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?

Foi útil?

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)))))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top