Tentando aprender F #, mas fiquei confuso ao tentar distinguir entre fold e reduzir . Fold parece fazer a mesma coisa, mas requer um parâmetro extra. Existe uma razão legítima para essas duas funções existirem ou elas existem para acomodar pessoas com diferentes origens? (Por exemplo: String e string em C #)
Aqui está o trecho de código copiado da amostra:
let sumAList list =
List.reduce (fun acc elem -> acc + elem) list
let sumAFoldingList list =
List.fold (fun acc elem -> acc + elem) 0 list
printfn "Are these two the same? %A "
(sumAList [2; 4; 10] = sumAFoldingList [2; 4; 10])
f#
functional-programming
reduce
fold
Wallace
fonte
fonte
fold f a l
pode ser escrito comoreduce f a::l
.fold
em termos dereduce
é mais complicado do que isso - o tipo de acumulador defold
não precisa ser o mesmo que o tipo de coisas da lista!Respostas:
Fold
usa um valor inicial explícito para o acumulador enquantoreduce
usa o primeiro elemento da lista de entrada como o valor inicial do acumulador.Isso significa que o acumulador e, portanto, o tipo de resultado devem corresponder ao tipo de elemento da lista, enquanto eles podem diferir,
fold
pois o acumulador é fornecido separadamente. Isso se reflete nos tipos:Além disso,
reduce
lança uma exceção em uma lista de entrada vazia.fonte
fold
, você pode simplesmente adicionar esse valor inicial ao início da lista e fazerreduce
? Qual é o objetivofold
então?'state -> 'a -> 'state
para dobra vs'a -> 'a -> 'a
para reduzir, portanto, reduz o tipo de resultado ao mesmo que o tipo de elemento. Veja a resposta de Tomas Petricek abaixo.Além do que Lee disse, você pode definir
reduce
em termos defold
, mas não (facilmente) o contrário:O fato de
fold
usar um valor inicial explícito para o acumulador também significa que o resultado dafold
função pode ter um tipo diferente do tipo de valores na lista. Por exemplo, você pode usar o acumulador do tipostring
para concatenar todos os números em uma lista em uma representação textual:Ao usar
reduce
, o tipo de acumulador é igual ao tipo de valores na lista - isso significa que, se você tiver uma lista de números, o resultado deverá ser um número. Para implementar a amostra anterior, você teria que converter os números emstring
primeiro e depois acumular:fonte
fold' & its ability to express
reduzir '. Algumas línguas têm um conceito de quiralidade estrutural (Haskell, estou olhando para você). Você pode dobrar para a esquerda ou para a direita, visualmente representado neste wiki ( en.wikipedia.org/wiki/Fold_%28higher-order_function ). Com uma construção de identidade, os outros dois operadores FP "fundamentais" (filter e fmap) também são implementáveis com uma construção de linguagem de primeira classe `fold 'existente (todas elas são construções isomórficas). ( Cs.nott.ac.uk/~pszgmh/fold.pdf ) Ver: Hott, Princeton (Esta seção de comentários é demasiado pequeno para conter ..)Vejamos suas assinaturas:
Existem algumas diferenças importantes:
reduce
funcione apenas em um tipo de elemento, o acumulador e os elementos da listafold
podem estar em tipos diferentes.Com
reduce
, você aplica uma funçãof
a todos os elementos da lista, começando pelo primeiro:f (... (f i0 i1) i2 ...) iN
.Com
fold
, você aplicaf
a partir do acumuladors
:f (... (f s i0) i1 ...) iN
.Portanto,
reduce
resulta em umaArgumentException
lista vazia. Além disso,fold
é mais genérico quereduce
; você pode usarfold
para implementarreduce
facilmente.Em alguns casos, o uso
reduce
é mais sucinto:ou mais conveniente se não houver um acumulador razoável:
Em geral,
fold
é mais poderoso com um acumulador de um tipo arbitrário:fonte
fold
é uma função muito mais valiosa do quereduce
. Você pode definir muitas funções diferentes em termos defold
.reduce
é apenas um subconjunto defold
.Definição de fold:
Exemplos de funções definidas em termos de dobra:
fonte
fold
de forma diferente deList.fold
como o tipo deList.fold
é('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
, mas no seu caso('a -> 'b -> 'b) -> 'b -> 'a list -> 'b
. Apenas para deixar explícito. Além disso, sua implementação do append está errada. Funcionaria se você adicionar uma ligação a ela, por exemploList.collect id (fold (fun x y -> x :: y) [] [xs;ys])
, ou substituir contras pelo operador de acréscimo. Portanto, anexar não é o melhor exemplo nesta lista.