2011-03-26 19 views
29

¿Por qué usar un operador de tubería hacia atrás en lugar de un encadenamiento de función?¿Por qué utilizar un operador de tubería hacia atrás en lugar de cadena de funciones?

let distanceFromOrigin aPoint = 
    let square x = x * x 
    sqrt (square aPoint.x + square aPoint.y) 

vs

let distanceFromOrigin aPoint = 
    let square x = x * x 
    sqrt <| square aPoint.x + square aPoint.y 
+1

¿Es diferente de '' $ operador de Haskell? –

+2

Es la misma definición, con una asociatividad diferente (por lo que es un poco menos útil). – Laurent

+1

http://theburningmonk.com/2011/09/fsharp-pipe-forward-and-pipe-backward/ –

Respuesta

33

Debido a la asociatividad izquierda (f <| g <| x se analiza como (f <| g) <| x y por desgracia no como f <| (g <| x) lo que equivale a x |> g |> f), me pareció útil sólo cuando se desea eliminar paréntesis (en lugar de f (long expression), escriba f <| long expression).

+3

+1 Sí, creo que este es el punto principal. (Agregué un poco de formato a tu respuesta, espero que esté bien) –

20

Elegir entre f x, x |> f y f <| x es principalmente una cuestión de estilo . No hay una regla absoluta para elegir uno en lugar del otro . El operador |> es muy popular, y es una buena idea usarlo.

<| es menos frecuente, pero si nos fijamos en las fuentes del compilador, encontrará un par de usos de . Por ejemplo:

raise <| System.InvalidOperationException (SR.GetString(SR.QillFormedAppOrLet)) 

if info.precision then 
    failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(ch.ToString()) 

<| se utiliza para eliminar un paréntesis, y creo que hacer el código más legible cuando se usa con cuidado. Cuando lo ves, sabes que la siguiente expresión es el argumento de tu función. Usted no tiene que buscar el paréntesis de cierre. Le sugiero que use con moderación, y por lo general debería evitar la mezcla <| y |> en la misma expresión, ya que puede ser muy confuso .

A veces me gusta usar este operador para crear un "bloque", con una palabra clave fun o lazy.

let f (l: Lazy<_>) =() 
let g (f: _ -> _ -> _) =() 

f <| lazy 
    let x = 1 + 1 
    x * x 

g <| fun x y -> 
    let sqr n = n * n 
    sqr x + sqr y 

El bloque se basa en la muesca, por lo que encaja muy bien en F # código. Gracias al operador <|, no necesita un paréntesis final.

4

a Scott Wlaschin señaló here, el operador tubo hacia atrás es útil si necesita pasar en datos como el primer parámetro (en lugar de la última) en algún lugar a lo largo de una cadena de tubos de. Considere lo siguiente:

let replace (replaceThis: string) (withThis: string) (input: string) = 
    input.Replace(replaceThis, withThis) 

let joinWith (input1: string) (input2: string) = 
    input1 + " " + input2 

let testString = "Happy" 

let amendedString = testString 
        |> replace "H" "Cr" 
        |> joinWith "birthday" 

amendedString es "cumpleaños es malísima". Digamos que, en su lugar, quiero que sea un "cumpleaños chiflado". Puedo lograr que al utilizar el operador de la tubería hacia atrás:

let amendedString = testString 
        |> replace "H" "Cr" 
        |> joinWith <| "birthday" 

Ahora amendedString es "cumpleaños es malísima", que es lo que quiero.

Cuestiones relacionadas