He estado leyendo Real World Haskell , y me estoy acercando al final, pero una cuestión de estilo me ha estado fastidiando con los operadores (.)
y ($)
.
Cuando escribe una función que es una composición de otras funciones, la escribe así:
f = g . h
Pero cuando aplicas algo al final de esas funciones, lo escribo así:
k = a $ b $ c $ value
Pero el libro lo escribiría así:
k = a . b . c $ value
Ahora, para mí se ven funcionalmente equivalentes, hacen exactamente lo mismo en mis ojos. Sin embargo, cuanto más miro, más veo a las personas que escriben sus funciones de la manera en que lo hace el libro: componer (.)
primero y luego solo al final usar ($)
para agregar un valor para evaluar el lote (nadie lo hace con muchas composiciones en dólares) .
¿Hay alguna razón para usar los libros que sea mucho mejor que usar todos los ($)
símbolos? ¿O hay alguna mejor práctica aquí que no estoy obteniendo? ¿O es superfluo y no debería preocuparme en absoluto?
fuente
k = a $ b $ c value
a . b $ c value
que no me gusta tanto como el tercer ejemplo, pero guarda algunos caracteres.Respuestas:
Creo que puedo responder esto desde la autoridad.
No hay una razón especial. Bryan y yo preferimos reducir el ruido de la línea.
.
es más silencioso que$
. Como resultado, el libro usa laf . g . h $ x
sintaxis.fuente
f.g.h
como una nueva creación inteligentef(g(h()))
. Ahora están llamando a una nueva función, aunque anónima, que crearon en lugar de simplemente encadenar un gran diccionario de llamadas a funciones prefabricadas como un usuario de PHP.De hecho, son equivalentes: tenga en cuenta que el
$
operador no hace, esencialmente, nada.f $ x
evalúa af x
. El propósito de$
es su comportamiento de fijación: derecho-asociativo y precedencia mínima. Al eliminar$
y usar paréntesis para agrupar en lugar de precedencia infija, los fragmentos de código se ven así:y
La razón para preferir la
.
versión sobre la$
versión es la misma razón para preferir ambas sobre la versión entre paréntesis anterior: atractivo estético.Sin embargo, algunos podrían preguntarse si el uso de operadores de infijo en lugar de paréntesis se basa en una necesidad subconsciente de evitar cualquier posible parecido con Lisp (es broma ... ¿creo?).
fuente
Agregaría eso
f . g $ x
,f . g
es una unidad sintáctica significativa.Mientras tanto, en
f $ g $ x
,f $ g
no es una unidad significativa. Una cadena de$
es posiblemente más imperativa: primero obtenga el resultadog
dex
, luego hágalof
, luego hágalofoo
, luego etc.Mientras tanto, una cadena de
.
es posiblemente más declarativa y, en cierto sentido, más cercana a una vista centrada en el flujo de datos: componga una serie de funciones y, en última instancia, las aplique a algo.fuente
$
operador parece comportarse de manera similar al<|
operador en F #. Creo que ambos se definen igual, de hecho, en F #(<|) a b = a b
y en Haskella $ b = a b
, que son esencialmente equivalentes.(<|) b a = a b
en F #, ya que se usa como[1; 2; 3; 4; 5] <| List.map ((+) 1)
, si la memoria sirve.<|
operador pasa el valor a la función, en lugar de pasar la función al valor; en su lugar, su ejemplo de código funcionaría con el|>
operador.Para mí, creo que la respuesta es (a) la pulcritud, como dijo Don ; y (b) encuentro que cuando estoy editando código, mi función puede terminar en un estilo libre de puntos, y luego todo lo que tengo que hacer es eliminar el último en
$
lugar de regresar y cambiar todo. Un punto menor, sin duda, pero agradable.fuente
Hay una discusión interesante de esta pregunta en este hilo de Haskell-Cafe . Aparentemente, hay un punto de vista minoritario que sostiene que la asociatividad correcta
$
es "simplemente errónea" , y elegirf . g . h $ x
sobref $ g $ h $ x
es una forma de esquivar el problema.fuente
$!
también tiene la asociatividad correcta "claramente equivocada" - ¿Por qué es $ operador derecho-asociativo? .Es solo una cuestión de estilo. Sin embargo, la forma en que lo hace el libro tiene más sentido para mí. Compone todas las funciones y luego lo aplica al valor.
Su método se ve extraño, y el último
$
es innecesario.Sin embargo, realmente no importa. En Haskell, generalmente hay muchas, muchas formas correctas de hacer lo mismo.
fuente
Me doy cuenta de que esta es una pregunta muy antigua, pero creo que hay otra razón para esto que no se ha mencionado.
Si está declarando una nueva función sin puntos
f . g . h
, el valor que pase se aplicará automáticamente. Sin embargo, si escribef $ g $ h
, no funcionará.Creo que la razón por la que el autor prefiere el método de composición es porque lleva a una buena práctica de desarrollar funciones.
fuente