In Haskell the following expression:
a \b -> c $ d
is either
• Invalid
• (a (\b ->c)) d
• (a (\b -> (c d))
And why?
In Haskell the following expression:
a \b -> c $ d
is either
• Invalid
• (a (\b ->c)) d
• (a (\b -> (c d))
And why?
It’s invalid in vanilla Haskell because a lambda cannot be used directly as an argument to a function without an intervening operator. The correct version needs to use $ or parentheses:
a \b -> c $ d
a $ \b -> c $ d
a ( \b -> c $ d )
However, there is no fundamental reason that a lambda (or case, if, do, or let expression) should not be allowed there, because it’s not ambiguous. The BlockArguments extension (added in GHC 8.6.1) allows these syntactic constructs directly as arguments to functions. With that enabled, it parses the same as above, as:
(a (\b -> (c $ d))
The reason this does not parse as *(a (\b -> c)) d is that the scope of a lambda is defined in the Haskell Report §3 as extending as far rightward as possible (emphasis added):
The grammar is ambiguous regarding the extent of lambda abstractions, let expressions, and conditionals. The ambiguity is resolved by the meta-rule that each of these constructs extends as far to the right as possible.
In other words, the body of the lambda can be thought of as having lower precedence than any other expression. This notation is borrowed directly from lambda calculus, in which a λb. c d is the same as (a (λb. (c d))).
Note that I haven’t removed the $ here: these two expressions are different, even though they evaluate to the same result:
f x
f $ x
The first is an application of the function f to the argument x; the second is an application of the operator ($) to the arguments f and x. Like all infix operators, it’s syntactic sugar for a normal prefix function call:
($) f x
($) is defined as a right-associative operator (i.e. x $ y $ z = x $ (y $ z), not *(x $ y) $ z) with the lowest operator precedence, with the declaration infixr 0 in the Prelude. You can view information about an operator with the :info (or :i) command in GHCi:
> :info $
($) :: (a -> b) -> a -> b -- Defined in ‘GHC.Base’
infixr 0 $