I found precedence and associativity is a big obstacle for me to understand what the grammar is trying to express at first glance to haskell code.
For example,
blockyPlain :: Monad m => m t -> m t1 -> m (t, t1)
blockyPlain xs ys = xs >>= \x -> ys >>= \y -> return (x, y)
By experiment, I finally got it means,
blockyPlain xs ys = xs >>= (\x -> (ys >>= (\y -> return (x, y))))
instead of
blockyPlain xs ys = xs >>= (\x -> ys) >>= (\y -> return (x, y))
Which works as:
*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)]
I can get info from ghci for (>>=) as an operator, (infixl 1 >>=).
But there's no information for -> since it's not an operator.
Could someone of you guys give some reference to make this grammar thing easier to grasp?
The rule for lambdas is pretty simple: the body of the lambda extends as far to the right as possible without hitting an unbalanced parenthesis.
f (\x -> foo (bar baz) *** quux >>= quuxbar)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
body
A good rule of thumb seems to be that you can never make a custom operator that has precedence over built in syntactic constructs. For instance consider this example:
if b then f *** x else f *** y
Regardless of the associativity of ***
, no one would expect it to binds as:
(if b then f *** x else f) *** y
There aren't a lot of syntactic constructs in Haskell (do
and case
are a little special because of layout syntax) but let
can be used as another example:
(let x = y in y *** x) /= ((let x = y in y) *** x)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With