Buscar..


Introducción a los pliegues, con un puñado de ejemplos.

Los pliegues son funciones (de orden superior) usadas con secuencias de elementos. Se colapsan seq<'a> en 'b donde 'b es cualquier tipo (posiblemente todavía 'a ). Esto es un poco abstracto, así que veamos ejemplos prácticos concretos.

Cálculo de la suma de todos los números.

En este ejemplo, 'a es un int . Tenemos una lista de números y queremos calcular la suma de todos los números. Para sumar los números de la lista [1; 2; 3] escribimos

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

Permítanme explicar, porque estamos tratando con listas, usamos fold en el módulo List , por List.fold tanto List.fold . El primer argumento que fold quita es una función binaria, la carpeta . El segundo argumento es el valor inicial . fold comienza a plegar la lista aplicando consecutivamente la función de carpeta a los elementos de la lista comenzando con el valor inicial y el primer elemento. Si la lista está vacía, se devuelve el valor inicial!

La vista general esquemática de un ejemplo de ejecución se ve así:

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 función List.sum es aproximadamente List.fold add LanguagePrimitives.GenericZero donde el cero genérico lo hace compatible con enteros, flotadores, enteros grandes, etc.

Contando elementos en una lista ( count implementación)

Esto se hace casi de la misma manera que antes, pero al ignorar el valor real del elemento en la lista y en su lugar agregar 1.

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

Esto también se puede hacer así:

[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

Para que puedas definir el count siguiente manera:

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

Encontrando el máximo de la lista.

Esta vez usaremos List.reduce que es como List.fold pero sin un valor inicial, como en este caso donde no sabemos cuál es el tipo de los valores que comparamos:

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 

Encontrar el mínimo de una lista.

Al igual que al encontrar el máximo, la carpeta es diferente

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

Listas de concatenacion

Aquí estamos tomando la lista de listas La función de carpeta es el operador @

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

O podría usar operadores binarios como su función de carpeta:

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

Cálculo del factorial de un número.

La misma idea que al sumar los números, pero ahora los multiplicamos. si queremos el factorial de n , multiplicamos todos los elementos de la lista [1 .. n] . El código se convierte en:

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

Implementando forall , exists y contains

la función forall comprueba si todos los elementos en una secuencia satisfacen una condición. exists verificación si al menos un elemento en la lista cumple con la condición. Primero necesitamos saber cómo contraer una lista de valores bool . Bueno, ¡usamos pliegues por supuesto! Los operadores booleanos serán nuestras funciones de carpeta.

Para verificar si todos los elementos en una lista son true , los && con la función && con true como valor inicial.

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

Del mismo modo, para verificar si un elemento es true en una lista booleanos, lo colapsamos con el || operador con false como valor inicial:

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

Volver a forall y exists . Aquí tomamos una lista de cualquier tipo, usamos la condición para transformar todos los elementos a valores booleanos y luego la colapsamos:

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

Para comprobar si todos los elementos en [1; 2; 3; 4] son ​​más pequeños que 5:

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

Definir el método contains con exists :

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

O incluso

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

Ahora verifique si la lista [1 .. 5] contiene el valor 2:

contains 2 [1..5] // true

Implementación reverse :

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

Implementando map y 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]

¿Hay algo que el fold no pueda hacer? No lo sé realmente

Cálculo de la suma de todos los elementos de una lista

Para calcular la suma de términos (de tipo float, int o entero grande) de una lista de números, es preferible usar List.sum. En otros casos, List.fold es la función que mejor se adapta para calcular dicha suma.

  1. Suma de numeros complejos

En este ejemplo, declaramos una lista de números complejos y calculamos la suma de todos los términos en la lista.

Al comienzo del programa, agregue una referencia a System.Numerics

abrir System.Numerics

Para calcular la suma, inicializamos el acumulador al número complejo 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

Resultado:

(3, 51)
  1. Suma de números de tipo sindical.

Supongamos que una lista se compone de números de tipo union (float o int) y desea calcular la suma de estos números.

Declara antes del siguiente tipo de número:

type number = 
| Float of float
| Int of int

Calcule la suma de números de número de tipo de 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

Resultado:

13.5

El primer parámetro de la función, que representa el acumulador, es de tipo float y el segundo parámetro, que representa un elemento en la lista es de tipo de número. Pero antes de agregar, necesitamos usar una coincidencia de patrón y convertir a tipo float cuando elem es de tipo Int.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow