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.

  1. 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)
  1. 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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow