Ricerca…
Introduzione alle pieghe, con una manciata di esempi
Le pieghe sono funzioni (di ordine superiore) utilizzate con sequenze di elementi. Crollano seq<'a>
in 'b
dove 'b
è di qualsiasi tipo (eventualmente ancora 'a
). Questo è un po 'astratto, quindi lasciate entrare in esempi pratici concreti.
Calcolo della somma di tutti i numeri
In questo esempio, 'a
è un int
. Abbiamo una lista di numeri e vogliamo calcolare sommarne tutti i numeri. Per sommare i numeri della lista [1; 2; 3]
scriviamo
List.fold (fun x y -> x + y) 0 [1; 2; 3] // val it : int = 6
Lasciatemi spiegare, perché abbiamo a che fare con le liste, usiamo la fold
nel modulo List
, quindi List.fold
. il primo argomento fold
takes è una funzione binaria, la cartella . Il secondo argomento è il valore iniziale . fold
inizia a piegare la lista applicando consecutivamente la funzione cartella agli elementi della lista iniziando dal valore iniziale e dal primo elemento. Se la lista è vuota, viene restituito il valore iniziale!
La panoramica schematica di un esempio di esecuzione si presenta così:
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
La funzione List.sum
è approssimativamente List.fold add LanguagePrimitives.GenericZero
dove lo zero generico lo rende compatibile con interi, float, interi grandi ecc.
Conteggio degli elemets in un elenco ( count
dell'implementazione)
Questo viene fatto quasi come sopra, ma ignorando il valore reale dell'elemento nella lista e aggiungendo invece 1.
List.fold (fun x y -> x + 1) 0 [1; 2; 3] // val it : int = 3
Questo può anche essere fatto in questo modo:
[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
Quindi puoi definire il count
come segue:
let count xs =
xs
|> List.map (fun x -> 1)
|> List.fold (+) 0 // or List.sum
Trovare il massimo della lista
Questa volta useremo List.reduce
che è come List.fold
ma senza un valore iniziale come in questo caso in cui non sappiamo quale sia il tipo dei valori che stiamo confrontando:
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
Trovare il minimo di una lista
Proprio come quando si trova il massimo, la cartella è diversa
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
Elenchi concatenanti
Qui stiamo prendendo l'elenco delle liste La funzione cartella è l'operatore @
// [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]
Oppure potresti usare gli operatori binari come funzione della tua cartella:
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...
Calcolo del fattoriale di un numero
La stessa idea di quando si sommano i numeri, ma ora li moltiplichiamo. se vogliamo il fattoriale di n
moltiplessiamo tutti gli elementi nella lista [1 .. n]
. Il codice diventa:
// 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]
Implementare forall
, exists
e contains
la funzione forall
controlla se tutti gli elementi di una sequenza soddisfano una condizione. exists
controllo se almeno un elemento nell'elenco soddisfa la condizione. Per prima cosa dobbiamo sapere come comprimere un elenco di valori bool
. Bene, usiamo le pieghe ofcourse! gli operatori booleani saranno le nostre funzioni di cartella.
Per verificare se tutti gli elementi in una lista sono true
, li collassiamo con la funzione &&
con true
come valore iniziale.
List.fold (&&) true [true; true; true] // true
List.fold (&&) true [] // true, empty list -> return inital value
List.fold (&&) true [false; true] // false
Allo stesso modo, per verificare se un elemento è true
in una lista di valori booleani, lo collassiamo con ||
operatore con false
come valore iniziale:
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
Torna a forall
ed exists
. Qui prendiamo una lista di qualsiasi tipo, usiamo la condizione per trasformare tutti gli elementi in valori booleani e poi la comprimiamo:
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
Per verificare se tutti gli elementi in [1; 2; 3; 4] sono più piccoli di 5:
forall (fun n -> n < 5) [1 .. 4] // true
definire il metodo contains
con exists
:
let contains x xs = exists (fun y -> y = x) xs
O anche
let contains x xs = exists ((=) x) xs
Ora controlla se la lista [1 .. 5] contiene il valore 2:
contains 2 [1..5] // true
Attuazione al reverse
:
let reverse xs = List.fold (fun acc x -> x :: acc) [] xs
reverse [1 .. 5] // [5; 4; 3; 2; 1]
Implementazione di map
e 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]
C'è qualcosa fold
non si può fare? Non lo so davvero
Calcolo della somma di tutti gli elementi di una lista
Per calcolare la somma di termini (di tipo float, int o intero grande) di un elenco di numeri, è preferibile utilizzare List.sum In altri casi, List.fold è la funzione più adatta per calcolare tale somma.
- Somma di numeri complessi
In questo esempio, dichiariamo un elenco di numeri complessi e calcoliamo la somma di tutti i termini nell'elenco.
All'inizio del programma, aggiungi un riferimento a System.Numerics
apri System.Numerics
Per calcolare la somma, inizializziamo l'accumulatore al numero complesso 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
Risultato:
(3, 51)
- Somma dei numeri di tipo di unione
Supponiamo che una lista sia composta da numeri di tipo union (float o int) e voglia calcolare la somma di questi numeri.
Dichiarare prima del seguente tipo di numero:
type number =
| Float of float
| Int of int
Calcola la somma dei numeri del numero di tipo di una 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
Risultato:
13.5
Il primo parametro della funzione, che rappresenta l'accumulatore, è di tipo float e il secondo parametro, che rappresenta un elemento nell'elenco, è di tipo numero. Ma prima di aggiungere, dobbiamo usare un pattern matching e cast per digitare float quando elem è di tipo Int.