Essayer d'apprendre F # mais être confus en essayant de faire la distinction entre plier et réduire . Fold semble faire la même chose mais prend un paramètre supplémentaire. Existe-t-il une raison légitime pour que ces deux fonctions existent ou sont-elles là pour accueillir des personnes d'horizons différents? (Par exemple: chaîne et chaîne en C #)
Voici un extrait de code copié à partir de l'exemple:
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
la source
la source
fold f a l
peut être écrit commereduce f a::l
.fold
en œuvre en termes dereduce
est plus compliquée que cela - le type d'accumulateur defold
n'a pas besoin d'être le même que le type de choses dans la liste!Réponses:
Fold
prend une valeur initiale explicite pour l'accumulateur tandis quereduce
utilise le premier élément de la liste d'entrée comme valeur initiale de l'accumulateur.Cela signifie que l'accumulateur et donc le type de résultat doivent correspondre au type d'élément de liste, alors qu'ils peuvent différer
fold
car l'accumulateur est fourni séparément. Cela se reflète dans les types:De plus,
reduce
lance une exception sur une liste d'entrée vide.la source
fold
, vous pouvez simplement ajouter cette valeur initiale au début de la liste et fairereduce
? À quoi ça sertfold
alors?'state -> 'a -> 'state
pour le pli vs'a -> 'a -> 'a
pour réduire, ainsi la réduction contraint le type de résultat à être le même que le type d'élément. Voir la réponse de Tomas Petricek ci-dessous.En plus de ce que Lee a dit, vous pouvez définir
reduce
en termes defold
, mais pas (facilement) l'inverse:Le fait que cela
fold
prenne une valeur initiale explicite pour l'accumulateur signifie également que le résultat de lafold
fonction peut avoir un type différent du type de valeurs dans la liste. Par exemple, vous pouvez utiliser un accumulateur de typestring
pour concaténer tous les nombres d'une liste en une représentation textuelle:Lors de l'utilisation
reduce
, le type d'accumulateur est le même que le type de valeurs dans la liste - cela signifie que si vous avez une liste de nombres, le résultat devra être un nombre. Pour implémenter l'exemple précédent, vous devez d'abord convertir les nombresstring
, puis les accumuler:la source
fold' & its ability to express
réduire '. Certaines langues ont un concept de chiralité structurelle (Haskell je vous regarde) que vous pouvez replier à gauche ou à droite visuellement représenté dans ce wiki ( en.wikipedia.org/wiki/Fold_%28higher-order_function ). Avec une construction d'identité, les deux autres opérateurs FP «fondamentaux» (filtre et fmap) sont également implémentables avec une construction de langage de première classe «fold» existante (ce sont toutes des constructions isomorphes). ( cs.nott.ac.uk/~pszgmh/fold.pdf ) Voir: HoTT, Princeton (Cette section de commentaires est trop petite pour contenir ..)Regardons leurs signatures:
Il existe des différences importantes:
reduce
fonctionne que sur un seul type d'éléments, les éléments d'accumulateur et de liste dansfold
peuvent être de types différents.Avec
reduce
, vous appliquez une fonctionf
à chaque élément de liste en commençant par le premier:f (... (f i0 i1) i2 ...) iN
.Avec
fold
, vous appliquez àf
partir de l'accumulateurs
:f (... (f s i0) i1 ...) iN
.Par conséquent, il en
reduce
résulte uneArgumentException
liste vide. De plus,fold
est plus générique quereduce
; vous pouvez utiliserfold
pour mettre en œuvrereduce
facilement.Dans certains cas, l'utilisation
reduce
est plus succincte:ou plus pratique s'il n'y a pas d'accumulateur raisonnable:
En général,
fold
est plus puissant avec un accumulateur de type arbitraire:la source
fold
est une fonction beaucoup plus précieuse quereduce
. Vous pouvez définir de nombreuses fonctions différentes en termes defold
.reduce
est juste un sous-ensemble defold
.Définition du pli:
Exemples de fonctions définies en termes de pli:
la source
fold
différemmentList.fold
comme le type deList.fold
est('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
, mais dans votre cas('a -> 'b -> 'b) -> 'b -> 'a list -> 'b
. Juste pour le rendre explicite. De plus, votre implémentation de append est incorrecte. Cela fonctionnerait si vous y ajoutez une liaison, par exempleList.collect id (fold (fun x y -> x :: y) [] [xs;ys])
, ou si vous remplacez cons par l'opérateur append. L'ajout n'est donc pas le meilleur exemple de cette liste.