Recherche…


Introduction aux plis, avec quelques exemples

Les plis sont des fonctions (d'ordre supérieur) utilisées avec des séquences d'éléments. Ils réduisent seq<'a> en 'b'b est n'importe quel type (peut-être encore 'a ). Ceci est un peu abstrait, alors allons dans des exemples pratiques concrets.

Calcul de la somme de tous les nombres

Dans cet exemple, 'a est un int . Nous avons une liste de nombres et nous voulons calculer la somme de tous les nombres. Pour résumer les numéros de la liste [1; 2; 3] nous écrivons

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

Permettez-moi de vous expliquer, car nous avons affaire à des listes, nous utilisons fold dans le module List , donc List.fold . le premier argument fold est une fonction binaire, le dossier . Le second argument est la valeur initiale . fold commence à plier la liste en appliquant consécutivement la fonction de dossier aux éléments de la liste en commençant par la valeur initiale et le premier élément. Si la liste est vide, la valeur initiale est renvoyée!

La vue d'ensemble schématique d'un exemple d'exécution ressemble à ceci:

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 fonction List.sum est approximativement List.fold add LanguagePrimitives.GenericZero où le zéro générique le rend compatible avec les entiers, les flottants, les grands entiers, etc.

Comptage des élémets dans une liste ( count implémentation)

Cela se fait presque comme ci-dessus, mais en ignorant la valeur réelle de l'élément dans la liste et en ajoutant 1.

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

Cela peut aussi être fait comme ceci:

[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

Donc, vous pouvez définir count comme suit:

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

Trouver le maximum de liste

Cette fois, nous utiliserons List.reduce comme List.fold mais sans valeur initiale, car dans ce cas, nous ne connaissons pas le type des valeurs que nous comparons:

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 

Trouver le minimum d'une liste

Tout comme pour trouver le max, le dossier est différent

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

Listes concaténantes

Ici, nous prenons la liste des listes La fonction de dossier est l'opérateur @

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

Ou vous pouvez utiliser des opérateurs binaires comme fonction de dossier:

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

Calcul de la factorielle d'un nombre

Même idée qu'en sommant les nombres, mais maintenant on les multiplie. si on veut la factorielle de n on multiplie tous les éléments de la liste [1 .. n] . Le code devient:

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

La mise en œuvre forall , exists et contains

La fonction forall vérifie si tous les éléments d'une séquence satisfont à une condition. exists vérifie si au moins un élément de la liste satisfait à la condition. Nous devons d'abord savoir comment réduire une liste de valeurs bool . Eh bien, nous utilisons des plis de cours! Les opérateurs booléens seront nos fonctions de dossier.

Pour vérifier si tous les éléments d'une liste sont true nous les && avec la fonction && avec la valeur true comme valeur initiale.

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

De même, pour vérifier si un élément est true dans une liste booléenne, nous le réduisons avec le || opérateur avec false comme valeur initiale:

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

Retour à la forall et exists . Ici, nous prenons une liste de tout type, utilisons la condition pour transformer tous les éléments en valeurs booléennes et ensuite nous la réduisons:

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

Pour vérifier si tous les éléments dans [1; 2; 3; 4] sont plus petits que 5:

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

définir la méthode contains avec exists :

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

Ou même

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

Vérifiez maintenant si la liste [1 .. 5] contient la valeur 2:

contains 2 [1..5] // true

Mise en œuvre reverse :

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

Mise en œuvre de la map et du 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]

Y a-t-il quelque chose que le fold ne peut pas faire? Je ne sais pas vraiment

Calcul de la somme de tous les éléments d'une liste

Pour calculer la somme des termes (de type float, int ou big entier) d'une liste de nombres, il est préférable d'utiliser List.sum. Dans d'autres cas, List.fold est la fonction la mieux adaptée pour calculer une telle somme.

  1. Somme de nombres complexes

Dans cet exemple, nous déclarons une liste de nombres complexes et nous calculons la somme de tous les termes de la liste.

Au début du programme, ajoutez une référence à System.Numerics

ouvrir System.Numerics

Pour calculer la somme, nous initialisons l'accumulateur au nombre complexe 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

Résultat:

(3, 51)
  1. Somme des nombres de type union

Supposons qu'une liste soit composée de nombres de type union (float ou int) et que vous souhaitez calculer la somme de ces nombres.

Déclarez avant le type de numéro suivant:

type number = 
| Float of float
| Int of int

Calculez la somme des nombres de type numéro d'une 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

Résultat:

13.5

Le premier paramètre de la fonction, qui représente l'accumulateur, est de type float et le second paramètre, qui représente un élément de la liste, est de type numéro. Mais avant d'ajouter, nous devons utiliser une correspondance de modèle et la convertir en type float quand elem est de type Int.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow