Haskell Precedence: Lambda y operador
grammar operator-precedence (2)
La regla para las lambdas es bastante simple: el cuerpo de la lambda se extiende lo más a la derecha posible sin golpear un paréntesis desequilibrado.
f (/x -> foo (bar baz) *** quux >>= quuxbar)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
body
Encontré la precedencia y la asociatividad es un gran obstáculo para que entienda lo que la gramática está tratando de expresar a primera vista con el código de haskell.
Por ejemplo,
blockyPlain :: Monad m => m t -> m t1 -> m (t, t1)
blockyPlain xs ys = xs >>= /x -> ys >>= /y -> return (x, y)
Por experimento, finalmente lo entendí,
blockyPlain xs ys = xs >>= (/x -> (ys >>= (/y -> return (x, y))))
en lugar de
blockyPlain xs ys = xs >>= (/x -> ys) >>= (/y -> return (x, y))
Que funciona como:
*Main> blockyPlain [1,2,3] [4,5,6]
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]
Puedo obtener información de ghci para (>> =) como operador, (infijo 1 >> =).
Pero no hay información para -> ya que no es un operador.
¿Podría alguien de ustedes dar alguna referencia para hacer que esta cosa de la gramática sea más fácil de entender?
Una buena regla general parece ser que nunca se puede hacer un operador personalizado que tenga prioridad sobre las construcciones sintácticas integradas. Por ejemplo, considere este ejemplo:
if b then f *** x else f *** y
Independientemente de la asociatividad de ***
, nadie esperaría que se uniera como:
(if b then f *** x else f) *** y
No hay muchas construcciones sintácticas en Haskell ( do
y case
son un poco especiales debido a la sintaxis del diseño), pero podemos usarlas como otro ejemplo:
(let x = y in y *** x) /= ((let x = y in y) *** x)