Suche…
Intro zum Falten, mit einer Handvoll Beispielen
Falten sind (Funktionen höherer Ordnung), die mit Elementsequenzen verwendet werden. Sie reduzieren seq<'a>
zu 'b
wobei 'b
ein beliebiger Typ ist (möglicherweise noch 'a
). Dies ist ein bisschen abstrakt, also lassen Sie uns in konkrete praktische Beispiele einsteigen.
Berechnung der Summe aller Zahlen
In diesem Beispiel ist 'a
ein int
. Wir haben eine Liste von Zahlen und wir wollen die Summe aller Zahlen berechnen. Um die Zahlen der Liste zu summieren [1; 2; 3]
wir schreiben
List.fold (fun x y -> x + y) 0 [1; 2; 3] // val it : int = 6
Lassen Sie mich erklären, weil wir mit Listen zu tun haben , die wir verwenden fold
in der List
Modul, daher List.fold
. Das erste Argument fold
ist eine binäre Funktion, der Ordner . Das zweite Argument ist der Anfangswert . fold
beginnt die Liste zu fold
indem die Ordnerfunktion nacheinander auf Elemente in der Liste angewendet wird, beginnend mit dem Anfangswert und dem ersten Element. Wenn die Liste leer ist, wird der Anfangswert zurückgegeben!
Die schematische Übersicht eines Ausführungsbeispiels sieht folgendermaßen aus:
let add x y = x + y // this is our folder (a binary function, takes two arguments)
List.fold add 0 [1; 2; 3;]
=> List.fold add (add 0 1) [2; 3]
// the binary function is passed again as the folder in the first argument
// the initial value is updated to add 0 1 = 1 in the second argument
// the tail of the list (all elements except the first one) is passed in the third argument
// it becomes this:
List.fold add 1 [2; 3]
// Repeat untill the list is empty -> then return the "inital" value
List.fold add (add 1 2) [3]
List.fold add 3 [3] // add 1 2 = 3
List.fold add (add 3 3) []
List.fold add 6 [] // the list is empty now -> return 6
6
Die Funktion List.sum
ist ungefähr List.fold add LanguagePrimitives.GenericZero
wobei die generische Null für Ganzzahlen, Fließkommas, große Ganzzahlen usw. List.sum
ist.
Elemente in einer Liste zählen ( count
implementieren)
Dies geschieht fast genauso wie oben, jedoch wird der tatsächliche Wert des Elements in der Liste ignoriert und stattdessen 1 hinzugefügt.
List.fold (fun x y -> x + 1) 0 [1; 2; 3] // val it : int = 3
Das kann man auch so machen:
[1; 2; 3]
|> List.map (fun x -> 1) // turn every elemet into 1, [1; 2; 3] becomes [1; 1; 1]
|> List.sum // sum [1; 1; 1] is 3
Sie können also die count
wie folgt definieren:
let count xs =
xs
|> List.map (fun x -> 1)
|> List.fold (+) 0 // or List.sum
Das Maximum der Liste finden
Diesmal verwenden wir List.reduce
das wie List.fold
aber ohne einen Anfangswert. In diesem Fall wissen wir nicht, was der Typ der Werte ist, die wir miteinander vergleichen:
let max x y = if x > y then x else y
// val max : x:'a -> y: 'a -> 'a when 'a : comparison, so only for types that we can compare
List.reduce max [1; 2; 3; 4; 5] // 5
List.reduce max ["a"; "b"; "c"] // "c", because "c" > "b" > "a"
List.reduce max [true; false] // true, because true > false
Das Minimum einer Liste finden
Genau wie beim Finden des Maximums unterscheidet sich der Ordner
let min x y = if x < y then x else y
List.reduce min [1; 2; 3; 4; 5] // 1
List.reduce min ["a"; "b"; "c"] // "a"
List.reduce min [true; false] // false
Listen verketten
Hier nehmen wir eine Liste der Listen auf. Die Ordnerfunktion ist der @
-Operator
// [1;2] @ [3; 4] = [1; 2; 3; 4]
let merge xs ys = xs @ ys
List.fold merge [] [[1;2;3]; [4;5;6]; [7;8;9]] // [1;2;3;4;5;6;7;8;9]
Oder Sie können binäre Operatoren als Ordnerfunktion verwenden:
List.fold (@) [] [[1;2;3]; [4;5;6]; [7;8;9]] // [1;2;3;4;5;6;7;8;9]
List.fold (+) 0 [1; 2; 3] // 6
List.fold (||) false [true; false] // true, more on this below
List.fold (&&) true [true; false] // false, more on this below
// etc...
Berechnung der Fakultät einer Zahl
Dieselbe Idee wie beim Summieren der Zahlen, aber jetzt multiplizieren wir sie. Wenn wir die Fakultät von n
wollen, multiplizieren wir alle Elemente in der Liste [1 .. n]
. Code wird zu:
// the folder
let times x y = x * y
let factorial n = List.fold times 1 [1 .. n]
// Or maybe for big integers
let factorial n = List.fold times 1I [1I .. n]
Die Implementierung forall
, exists
und contains
Die Funktion forall
prüft, ob alle Elemente einer Sequenz eine Bedingung erfüllen. exists
überprüft , ob atleast ein Element in der Liste die Bedingung erfüllen. Zuerst müssen wir wissen, wie eine Liste von bool
Werten bool
. Nun, wir verwenden natürlich Kursfalten! boolesche Operatoren werden unsere Ordnerfunktionen sein.
Um zu überprüfen, ob alle Elemente in einer Liste true
sind, true
wir sie mit der Funktion &&
mit dem Anfangswert true
.
List.fold (&&) true [true; true; true] // true
List.fold (&&) true [] // true, empty list -> return inital value
List.fold (&&) true [false; true] // false
Um zu überprüfen, ob ein Element in einem Listen-Boolean true
ist true
reduzieren wir es mit dem ||
Operator mit false
als Anfangswert:
List.fold (||) false [true; false] // true
List.fold (||) false [false; false] // false, all are false, no element is true
List.fold (||) false [] // false, empty list -> return inital value
Zurück zu forall
und exists
. Hier nehmen wir eine Liste eines beliebigen Typs, verwenden die Bedingung, um alle Elemente in boolesche Werte umzuwandeln, und reduzieren diese dann:
let forall condition elements =
elements
|> List.map condition // condition : 'a -> bool
|> List.fold (&&) true
let exists condition elements =
elements
|> List.map condition
|> List.fold (||) false
Um zu überprüfen, ob alle Elemente in [1; 2; 3; 4] sind kleiner als 5:
forall (fun n -> n < 5) [1 .. 4] // true
Definiere die contains
Methode mit exists
:
let contains x xs = exists (fun y -> y = x) xs
Oder auch
let contains x xs = exists ((=) x) xs
Prüfen Sie nun, ob die Liste [1 .. 5] den Wert 2 enthält:
contains 2 [1..5] // true
reverse
:
let reverse xs = List.fold (fun acc x -> x :: acc) [] xs
reverse [1 .. 5] // [5; 4; 3; 2; 1]
map
und filter
implementieren
let map f = List.fold (fun acc x -> List.append acc [f x]) List.empty
// map (fun x -> x * x) [1..5] -> [1; 4; 9; 16; 25]
let filter p = Seq.fold (fun acc x -> seq { yield! acc; if p(x) then yield x }) Seq.empty
// filter (fun x -> x % 2 = 0) [1..10] -> [2; 4; 6; 8; 10]
Gibt es etwas, was nicht fold
kann? Ich weiß es nicht wirklich
Berechnung der Summe aller Elemente einer Liste
Um die Summe der Terme (vom Typ float, int oder big integer) einer Zahlenliste zu berechnen, ist List.sum zu bevorzugen. In anderen Fällen ist List.fold die am besten geeignete Funktion zur Berechnung einer solchen Summe.
- Summe der komplexen Zahlen
In diesem Beispiel deklarieren wir eine Liste komplexer Zahlen und berechnen die Summe aller Terme in der Liste.
Fügen Sie zu Beginn des Programms einen Verweis auf System.Numerics hinzu
Öffnen Sie System.Numerics
Um die Summe zu berechnen, initialisieren wir den Akkumulator mit der komplexen Zahl 0.
let clist = [new Complex(1.0, 52.0); new Complex(2.0, -2.0); new Complex(0.0, 1.0)]
let sum = List.fold (+) (new Complex(0.0, 0.0)) clist
Ergebnis:
(3, 51)
- Summe der Nummern des Unionstyps
Angenommen, eine Liste besteht aus Nummern des Typs union (float oder int) und möchte die Summe dieser Zahlen berechnen.
Deklarieren Sie vor dem folgenden Nummerntyp:
type number =
| Float of float
| Int of int
Berechnen Sie die Summe der Typennummern einer Liste:
let list = [Float(1.3); Int(2); Float(10.2)]
let sum = List.fold (
fun acc elem ->
match elem with
| Float(elem) -> acc + elem
| Int(elem) -> acc + float(elem)
) 0.0 list
Ergebnis:
13.5
Der erste Parameter der Funktion, der den Akkumulator darstellt, ist vom Typ Float und der zweite Parameter, der ein Element in der Liste darstellt, hat die Typnummer. Bevor wir jedoch hinzufügen, müssen wir einen Mustervergleich verwenden und den Typ float verwenden, wenn elem vom Typ Int ist.