Der Versuch, F # zu lernen, war jedoch verwirrt, als er versuchte, zwischen Falten und Reduzieren zu unterscheiden . Fold scheint dasselbe zu tun , benötigt jedoch einen zusätzlichen Parameter. Gibt es einen legitimen Grund für die Existenz dieser beiden Funktionen oder sind sie dazu da, Menschen mit unterschiedlichem Hintergrund aufzunehmen? (ZB: String und String in C #)
Hier ist ein Code-Snippet, das aus dem Beispiel kopiert wurde:
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
quelle
quelle
fold f a l
kann als geschrieben werdenreduce f a::l
.fold
in Bezug aufreduce
ist komplizierter als das - die Art des Akkumulators vonfold
muss nicht mit der Art der Dinge in der Liste übereinstimmen !Antworten:
Fold
Nimmt einen expliziten Anfangswert für den Akkumulator, währendreduce
das erste Element der Eingabeliste als anfänglicher Akkumulatorwert verwendet wird.Dies bedeutet, dass der Akkumulator und damit der Ergebnistyp mit dem Listenelementtyp übereinstimmen müssen, während sie sich unterscheiden können,
fold
da der Akkumulator separat bereitgestellt wird. Dies spiegelt sich in den Typen wider:Darüber hinaus
reduce
löst eine Ausnahme auf eine leere Eingabeliste.quelle
fold
, können Sie diesen Anfangswert einfach am Anfang der Liste hinzufügen und tunreduce
? Was ist der Sinn vonfold
dann?'state -> 'a -> 'state
Für Falz und'a -> 'a -> 'a
für Reduzieren. Reduziert also, dass der Ergebnistyp mit dem Elementtyp identisch ist. Siehe die Antwort von Tomas Petricek unten.Zusätzlich zu dem, was Lee sagte, können Sie festlegen ,
reduce
in Bezug auffold
, aber nicht (leicht) umgekehrt:Die Tatsache, dass
fold
ein expliziter Anfangswert für den Akkumulator verwendet wird, bedeutet auch, dass das Ergebnis derfold
Funktion einen anderen Typ haben kann als der Wertetyp in der Liste. Beispielsweise können Sie einen Akkumulator vom Typ verwenden,string
um alle Zahlen in einer Liste zu einer Textdarstellung zu verketten:Bei Verwendung entspricht
reduce
der Akkumulatortyp dem Wertetyp in der Liste. Wenn Sie also eine Liste mit Zahlen haben, muss das Ergebnis eine Zahl sein. Um das vorherige Beispiel zu implementieren, müssen Siestring
zuerst die Zahlen in konvertieren und dann akkumulieren:quelle
fold' & its ability to express
Reduzierung '. Einige Sprachen haben ein Konzept der strukturellen Chiralität (Haskell, ich sehe dich an), das Sie in diesem Wiki ( en.wikipedia.org/wiki/Fold_%28higher-order_function ) visuell nach links oder rechts falten können . Mit einem Identitätskonstrukt können die beiden anderen "grundlegenden" FP-Operatoren (Filter und fmap) auch mit einem vorhandenen erstklassigen "Fold" -Sprachenkonstrukt implementiert werden (alle sind isomorphe Konstrukte). ( cs.nott.ac.uk/~pszgmh/fold.pdf ) Siehe: HoTT, Princeton (Dieser Kommentarbereich ist zu klein, um ihn zu enthalten ..)Schauen wir uns ihre Unterschriften an:
Es gibt einige wichtige Unterschiede:
reduce
für einenfold
Elementtyp gearbeitet wird , können sich der Akkumulator und die Listenelemente in unterschiedlichen Typen befinden.Mit
reduce
wenden Sie eine Funktionf
auf jedes Listenelement ab dem ersten an:f (... (f i0 i1) i2 ...) iN
.Mit
fold
bewerben Sie sichf
ab dem Akkus
:f (... (f s i0) i1 ...) iN
.Daher wird
reduce
eineArgumentException
leere Liste angezeigt. Darüber hinausfold
ist generischer alsreduce
; Sie können verwendenfold
, umreduce
einfach zu implementieren .In einigen Fällen ist die Verwendung
reduce
prägnanter:oder bequemer, wenn es keinen vernünftigen Akku gibt:
Im Allgemeinen
fold
ist mit einem Akkumulator eines beliebigen Typs leistungsfähiger:quelle
fold
ist eine viel wertvollere Funktion alsreduce
. Sie können viele verschiedene Funktionen in Bezug auf definierenfold
.reduce
ist nur eine Teilmenge vonfold
.Definition der Falte:
Beispiele für Funktionen, die in Bezug auf Fold definiert sind:
quelle
fold
andersList.fold
als die Art vonList.fold
ist('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
, aber in Ihrem Fall('a -> 'b -> 'b) -> 'b -> 'a list -> 'b
. Nur um es explizit zu machen. Außerdem ist Ihre Implementierung von append falsch. Es würde funktionieren, wenn Sie eine Bindung hinzufügen, z. B.List.collect id (fold (fun x y -> x :: y) [] [xs;ys])
oder Nachteile durch den Append-Operator ersetzen. Daher ist Anhängen nicht das beste Beispiel in dieser Liste.