Sök…


Introduktion till veck, med en handfull exempel

Vikningar är (högre ordning) funktioner som används med sekvenser av element. De kollapsar seq<'a> till 'b där 'b är vilken typ som helst (kanske fortfarande 'a ). Det här är lite abstrakt så att vi får konkreta praktiska exempel.

Beräkna summan av alla siffror

I detta exempel är 'a ett int . Vi har en lista med siffror och vi vill beräkna summan av alla nummer. För att summera listans siffror [1; 2; 3] vi skriver

List.fold (fun x y -> x + y) 0 [1; 2; 3] // val it : int = 6

Låt mig förklara, eftersom vi har att göra med listor, använder vi fold i List modulen därmed List.fold . det första argumentet fold krävs är en binär funktion, mappen. Det andra argumentet är initialvärdet . fold börjar vika listan genom att konsekvent tillämpa mappfunktionen på element i listan som börjar med det initiala värdet och det första elementet. Om listan är tom returneras initalsvärdet!

Schematisk översikt över ett exekveringsexempel ser så här ut:

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

Funktionen List.sum är ungefär List.fold add LanguagePrimitives.GenericZero där den generiska nollan gör den kompatibel med heltal, flottörer, stora heltal etc.

Räkna elemet i en lista (genomförande count )

Detta görs nästan samma sak som ovan, men genom att ignorera det faktiska värdet på elementet i listan och istället lägga till 1.

List.fold (fun x y -> x + 1) 0 [1; 2; 3] // val it : int = 3

Detta kan också göras så här:

[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

Så du kan definiera count sätt:

let count xs = 
    xs 
    |> List.map (fun x -> 1) 
    |> List.fold (+) 0 // or List.sum

Hitta maxlistan

Den här gången kommer vi att använda List.reduce som är som List.fold men utan ett initialt värde som i det här fallet där vi inte vet vad typen är av de värden vi jämför med:

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 

Hitta minsta lista

Precis som när du hittar max, är mappen annorlunda

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

Slå samman listor

Här tar vi en lista med listor Mappfunktionen är operatören @

// [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]

Eller så kan du använda binära operatörer som din mappfunktion:

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

Beräkning av faktorn för ett nummer

Samma idé som när vi summerar siffrorna, men nu multiplicerar vi dem. om vi vill ha fabriken om n multiplicerar vi alla element i listan [1 .. n] . Koden blir:

// 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] 

Implementering för forall , exists och contains

funktionen forall kontrollerar om alla element i en sekvens uppfyller ett villkor. exists kontrollerar om minst ett element i listan uppfyller villkoret. Först måste vi veta hur man kollapsar en lista med bool . Vi använder naturligtvis veck! booleska operatörer är våra mappfunktioner.

För att kontrollera om alla element i en lista är true kollapsar vi dem med && funktionen med true som initialvärde.

List.fold (&&) true [true; true; true] // true
List.fold (&&) true [] // true, empty list -> return inital value
List.fold (&&) true [false; true] // false

På samma sätt, för att kontrollera om ett element är true i en lista booleaner, kollapsar vi det med || operatör med false som initialvärde:

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

Tillbaka till forall och exists . Här tar vi en lista över vilken typ som helst, använder villkoret för att omvandla alla element till booleska värden och sedan kollapsar vi den ned:

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

För att kontrollera om alla element i [1; 2; 3; 4] är mindre än 5:

forall (fun n -> n < 5) [1 .. 4] // true

definiera contains metoden med exists :

let contains x xs = exists (fun y -> y = x) xs

Eller ens

let contains x xs = exists ((=) x) xs

Kontrollera nu om listan [1 .. 5] innehåller värdet 2:

contains 2 [1..5] // true

Genomförande reverse :

let reverse xs = List.fold (fun acc x -> x :: acc) [] xs
reverse [1 .. 5] // [5; 4; 3; 2; 1]

Implementera map och filter

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]

Finns det något fold inte kan göra? Jag vet inte riktigt

Beräkna summan av alla element i en lista

För att beräkna summan av termer (av typen flyta, int eller stort heltal) i en siffrelista är det att föredra att använda List.sum I andra fall är List.fold den funktion som är bäst lämpad för att beräkna en sådan summa.

  1. Summan av komplexa siffror

I det här exemplet förklarar vi en lista med komplexa siffror och vi beräknar summan av alla termer i listan.

Lägg till en referens till System.Numerics i början av programmet

öppna System.Numerics

För att beräkna summan initialiserar vi ackumulatorn till komplexet nummer 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

Resultat:

(3, 51)
  1. Summan av antalet unionstyp

Anta att en lista består av siffror av unionstyp (float eller int) och vill beräkna summan av dessa nummer.

Förklara före följande nummertyp:

type number = 
| Float of float
| Int of int

Beräkna summan av numren av typnumret i en lista:

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

Resultat:

13.5

Den första parametern för funktionen, som representerar ackumulatorn, är av typen float och den andra parametern, som representerar ett objekt i listan är av typnummer. Men innan vi lägger till måste vi använda ett mönstermatchning och gjuta för att skriva float när elem är av typ Int.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow