f#

f# - ¿Por qué funciona el operador de tubería?



(4)

Si el operador de tubería se crea así:

let (|>) f g = g f

Y usado así:

let result = [2;4;6] |> List.map (fun x -> x * x * x)

Entonces lo que parece hacer es tomar List.Map y ponerlo detrás (fun x -> x * x * x) Y no cambia nada sobre la posición de [2; 4; 6]

Entonces ahora se ve así:

let result2 = [2;4;6] (fun x -> x * x * x) List.map

Sin embargo, esto no funciona.

Solo estoy aprendiendo f # por primera vez ahora. Y esto me molestó mientras leía un libro sobre f #. Entonces podría aprender lo que me estoy perdiendo más tarde, pero decidí preguntar de todos modos.

Sin embargo, es obvio que me estoy perdiendo algo importante. Como puedo recrear fácilmente el operador de tubería. Pero no entiendo por qué funciona. Debo avergonzarme muy pronto a medida que aprendo más. Oh bien.


Como otros han dicho anteriormente, básicamente estás malinterpretando a qué se vería resuelto el resultado2. En realidad, se resolvería

List.map (fun x -> x * x * x) [2;4;6]

List.map toma dos argumentos: una función para aplicar a todos los elementos en una lista y una lista. (fun x -> x * x * x) es el primer argumento y [2;4;6] es el segundo.

Básicamente solo coloca lo que está a la izquierda de |> después del final de lo que está a la derecha.


Los corchetes que rodean |> significan que es un operador infijo para que pueda escribir su ejemplo

let result = (|>) [2;4;6] (List.map (fun x -> x * x * x))

Dado que |> aplica su primer argumento al segundo, esto es equivalente a

let result = (List.map (fun x -> x * x)) [2;4;6]


Si ingresa su definición de |> en fsi y observa la firma del operador derivada por inferencia de tipo, notará que val ( |> ) : ''a -> (''a -> ''b) -> ''b , es decir, argumento ''a dado para funcionar (''a -> ''b) produce ''b .

Ahora proyecta esta firma en tu expresión [2;4;6] |> List.map (fun x -> x * x * x) y obtendrás List.map (fun x -> x * x * x) [2;4;6] , donde el argumento es list [2;4;6] y la función se aplica parcialmente en función de un argumento List.map (fun x -> x * x * x) .


El operador de tuberías es simplemente azúcar sintáctica para llamadas a métodos encadenados. Es muy similar a cómo se expresan las expresiones linq en C #.

Explicación desde aquí :

Operador de tuberías delantero Me encanta este tipo. El operador de tubería Forward se define simplemente como:

let (|>) x f = f x

Y tiene una firma de tipo:

''a -> (''a -> ''b) -> ''b

Lo que se traduce en: dado un tipo genérico ''a, y una función que toma un'' a y devuelve un ''b, luego devuelve la aplicación de la función en la entrada.

En lugar de explicar esto, permítanme darles un ejemplo de dónde se puede usar:

// Take a number, square it, then convert it to a string, then reverse that string let square x = x * x let toStr (x : int) = x.ToString() let rev (x : string) = new String(Array.rev (x.ToCharArray())) // 512 -> 1024 -> "1024" -> "4201" let result = rev (toStr (square 512))

El código es muy directo, pero fíjate qué tan rebelde se ve la sintaxis. Todo lo que queremos hacer es tomar el resultado de un cálculo y pasarlo al siguiente cálculo. Podríamos reescribirlo introduciendo una serie de nuevas variables:

let step1 = square 512 let step2 = toStr step1 let step3 = rev step2 let result = step3

Pero ahora necesita mantener todas esas variables temporales correctas. Lo que hace el operador (|>) es tomar un valor, y ''reenviarlo'' a una función, esencialmente permitiéndole especificar el parámetro de una función antes de la llamada a la función. Esto simplifica drásticamente el código F # al permitirle canalizar funciones juntas, donde el resultado de uno pasa al siguiente. Entonces, para usar el mismo ejemplo, el código se puede escribir claramente como:

let result = 512 |> square |> toStr |> rev

Editar :

En F #, lo que realmente está haciendo con una llamada a método es tomar una función y luego aplicarla al parámetro que sigue, por lo que en su ejemplo sería List.map (fun x -> x * x * x) se aplica a [2;4;6] . Todo lo que hace el operador de tubería es tomar los parámetros en orden inverso y luego hacer la aplicación invirtiéndolos.

función: List.map (fun x -> x * x * x) : [2;4;6]

Sintaxis de llamada estándar F #: fg

Sintaxis de llamada F # invertida: gf

Estándar:

let var = List.map (fun x -> x * x * x) [2;4;6]

Invertido:

let var = [2;4;6] |> List.map (fun x -> x * x * x)