Esta é uma resposta suplementar para ajudar a explicar mapas e dobras. Para os exemplos abaixo, usarei esta lista. Lembre-se, esta lista é imutável, portanto nunca mudará:
var numbers = [1, 2, 3, 4, 5]
Vou usar números nos meus exemplos porque eles levam a códigos de fácil leitura. Lembre-se, no entanto, as dobras podem ser usadas para qualquer coisa que um loop imperativo tradicional possa ser usado.
Um mapa pega uma lista de algo e uma função e retorna uma lista que foi modificada usando a função. Cada item é passado para a função e se torna o que a função retornar.
O exemplo mais fácil disso é apenas adicionar um número a cada número em uma lista. Vou usar o pseudocódigo para torná-lo independente de idioma:
function add-two(n):
return n + 2
var numbers2 =
map(add-two, numbers)
Se você imprimisse numbers2
, veria [3, 4, 5, 6, 7]
qual é a primeira lista com 2 adicionadas a cada elemento. Observe que a função add-two
foi atribuída map
para uso.
As dobras s são semelhantes, exceto que a função que você precisa fornecer a elas deve receber 2 argumentos. O primeiro argumento é geralmente o acumulador (na dobra esquerda, que é o mais comum). O acumulador são os dados que são transmitidos durante o loop. O segundo argumento é o item atual da lista; assim como acima para a map
função.
function add-together(n1, n2):
return n1 + n2
var sum =
fold(add-together, 0, numbers)
Se você imprimisse sum
, veria a soma da lista de números: 15.
Aqui estão os argumentos para fold
fazer:
Esta é a função que estamos dando a dobra. A dobra passará a função do acumulador atual e o item atual da lista. O que quer que a função retorne se tornará o novo acumulador, que será passado para a função na próxima vez. É assim que você "lembra" dos valores quando faz um loop no estilo FP. Eu dei uma função que pega 2 números e os adiciona.
Este é o acumulador inicial; o que o acumulador inicia como antes de qualquer item da lista ser processado. Quando você soma números, qual é o total antes de adicionar números? 0, que eu passei como o segundo argumento.
Por fim, como no mapa, também passamos na lista de números para processamento.
Se as dobras ainda não fazem sentido, considere isso. Quando você escreve:
# Notice I passed the plus operator directly this time,
# instead of wrapping it in another function.
fold(+, 0, numbers)
Você está basicamente colocando a função passada entre cada item na lista e adicionando o acumulador inicial à esquerda ou à direita (dependendo se é uma dobra esquerda ou direita), então:
[1, 2, 3, 4, 5]
Torna-se:
0 + 1 + 2 + 3 + 4 + 5
^ Note the initial accumulator being added onto the left (for a left fold).
O que equivale a 15.
Use a map
quando desejar transformar uma lista em outra lista, do mesmo tamanho.
Use a fold
quando desejar transformar uma lista em um único valor, como somar uma lista de números.
Como o @Jorg apontou nos comentários, o "valor único" não precisa ser algo simples como um número; pode ser qualquer objeto único, incluindo uma lista ou uma tupla! O jeito que eu realmente clicou nas dobras para mim foi definir um mapa em termos de dobra. Observe como o acumulador é uma lista:
function map(f, list):
fold(
function(xs, x): # xs is the list that has been processed so far
xs.add( f(x) ) # Add returns the list instead of mutating it
, [] # Before any of the list has been processed, we have an empty list
, list)
Honestamente, depois de entender cada um, você perceberá que quase todos os ciclos podem ser substituídos por uma dobra ou um mapa.