Eu aprendi a diferença básica entre foldLeft
ereduceLeft
foldLeft:
- valor inicial deve ser passado
reduzirLeft:
- toma o primeiro elemento da coleção como valor inicial
- lança exceção se a coleção estiver vazia
Existe alguma outra diferença?
Algum motivo específico para ter dois métodos com funcionalidade semelhante?
scala
functional-programming
fold
higher-order-functions
Rajesh Pitty
fonte
fonte
Respostas:
Poucas coisas para mencionar aqui, antes de dar a resposta real:
left
, é sobre a diferença entre reduzir e dobrarVoltar à sua pergunta:
Aqui está a assinatura de
foldLeft
(também poderia ter sidofoldRight
para o ponto que eu vou fazer):E aqui está a assinatura de
reduceLeft
(novamente a direção não importa aqui)Estes dois parecem muito semelhantes e, portanto, causaram confusão.
reduceLeft
é um caso especial defoldLeft
(que, a propósito, significa que você às vezes pode expressar a mesma coisa usando qualquer um deles).Quando você chama
reduceLeft
say em aList[Int]
, literalmente reduz a lista inteira de números inteiros em um único valor, que será do tipoInt
(ou um supertipo deInt
, portanto[B >: A]
).Quando você chama o
foldLeft
say em um,List[Int]
ele dobrará a lista inteira (imagine rolar um pedaço de papel) em um único valor, mas esse valor nem precisa estar relacionado aInt
(daí[B]
).Aqui está um exemplo:
Este método pega um
List[Int]
e retorna umTuple2[List[Int], Int]
ou(List[Int], Int)
. Ele calcula a soma e retorna uma tupla com uma lista de números inteiros e sua soma. A propósito, a lista é retornada para trás, porque usamos emfoldLeft
vez defoldRight
.Assista ao One Fold para dominá-los para uma explicação mais aprofundada.
fonte
B
é um supertipoA
? PareceB
que na verdade deveria ser um subtipoA
, não um supertipo. Por exemplo, supondo queBanana <: Fruit <: Food
, se tivéssemos uma lista deFruit
s, parece que isso pode conter algunsBanana
s, mas se contivesse algumFood
s, o tipo seriaFood
correto? Portanto, nesse caso, seB
for um supertipo deA
e houver uma lista que contenhaB
s eA
s, a lista deverá ser do tipoB
, nãoA
. Você pode explicar essa discrepância?List[Banana]
pode ser reduzida para um únicoBanana
ou um únicoFruit
ou um únicoFood
. PorqueFruit :> Banana
e `Alimentos:> Banana '.Banana
pode conter umFruit
", o que não faz sentido. Sua explicação faz sentido - af
função que está sendo transmitidareduce()
pode resultar em aFruit
ou aFood
, o que significa queB
a assinatura deve ser uma superclasse, não uma subclasse.reduceLeft
é apenas um método de conveniência. É equivalente afonte
reducelft
emborafold
funciona em uma lista vazia enquantoreduce
não funciona.foldLeft
é mais genérico, você pode usá-lo para produzir algo completamente diferente do que você colocou originalmente. ConsiderandoreduceLeft
que só pode produzir um resultado final do mesmo tipo ou supertipo do tipo de coleção. Por exemplo:Ele
foldLeft
aplicará o fechamento com o último resultado dobrado (primeira vez usando o valor inicial) e o próximo valor.reduceLeft
por outro lado, primeiro combinará dois valores da lista e os aplicará ao fechamento. Em seguida, ele combinará o restante dos valores com o resultado acumulado. Vejo:Se a lista estiver vazia,
foldLeft
pode apresentar o valor inicial como resultado legal.reduceLeft
por outro lado, não possui um valor legal se não conseguir encontrar pelo menos um valor na lista.fonte
A razão básica de ambos estarem na biblioteca padrão Scala é provavelmente porque ambos estão na biblioteca padrão Haskell (chamada
foldl
efoldl1
). CasoreduceLeft
contrário, muitas vezes seria definido como um método de conveniência em diferentes projetos.fonte
Para referência,
reduceLeft
ocorrerá um erro se aplicado a um contêiner vazio com o seguinte erro.Retrabalhando o código para usar
é uma opção em potencial. Outra é usar a
reduceLeftOption
variante que retorna um resultado agrupado em Opção.fonte
Dos Princípios de Programação Funcional em Scala (Martin Odersky):
[ao contrário de
reduceLeft
, que gera uma exceção quando chamado em uma lista vazia.]O curso (consulte a aula 5.5) fornece definições abstratas dessas funções, que ilustram suas diferenças, embora sejam muito semelhantes no uso de correspondência e recursão de padrões.
Observe que
foldLeft
retorna um valor do tipoU
, que não é necessariamente o mesmo tipo queList[T]
, mas reduz a esquerda retorna um valor do mesmo tipo que a lista).fonte
Para realmente entender o que você está fazendo com dobra / redução, verifique isto: http://wiki.tcl.tk/17983 explicação muito boa. Depois de obter o conceito de dobra, reduzir será acompanhado pela resposta acima: list.tail.foldLeft (list.head) (_)
fonte