f# - ¿Por qué usar un operador de tubería hacia atrás en lugar del encadenamiento de funciones?
(3)
¿Por qué usar un operador de tubería hacia atrás en lugar de un encadenamiento 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
Como Scott Wlaschin señaló here , el operador de tubería hacia atrás es útil si necesita pasar datos como el primer parámetro (en lugar del último) en algún lugar a lo largo de una cadena de tuberías . Considera 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 Crappy". Digamos que quiero que sea "cumpleaños de Crappy" en su lugar. Puedo lograr eso usando el operador de tubería hacia atrás:
let amendedString = testString
|> replace "H" "Cr"
|> joinWith <| "birthday"
Ahora amendedString
es "Crappy birthday", que es lo que quiero.
Debido a la asociatividad izquierda ( f <| g <| x
se analiza como (f <| g) <| x
y, lamentablemente, no como f <| (g <| x)
que es equivalente a x |> g |> f
) , Lo encontré útil solo cuando quieres eliminar paréntesis (en lugar de f (long expression)
, escribes f <| long expression
).
Elegir entre fx
, x |> f
y f <| x
f <| x
es principalmente una cuestión de estilo. No hay una regla absoluta para elegir una en lugar de la otra. El operador |>
es muy popular, y es una buena idea usarlo.
<|
es menos frecuente, pero si busca en las fuentes del compilador, encontrará un par de usos. Por ejemplo:
raise <| System.InvalidOperationException (SR.GetString(SR.QillFormedAppOrLet))
if info.precision then
failwithf "%s" <| FSComp.SR.forFormatDoesntSupportPrecision(ch.ToString())
<|
se usa para eliminar un paréntesis, y creo que hace que el código sea más legible cuando se usa con cuidado. Cuando lo ves, sabes que la siguiente expresión es el argumento de tu función. No tienes que buscar el paréntesis de cierre. Le sugiero que lo use con moderación, y generalmente debe evitar mezclar <|
y |>
en la misma expresión, ya que puede ser muy confuso.
A veces disfruto usando 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 sangría, por lo que encaja bastante bien en el código F #. Gracias a los <|
operador, no necesita un paréntesis al final.