The release of GHC 8.6.1 brought the release of a language extension enabling an apparently small syntactic change: the
BlockArguments extension. During the discussion and implementation phase, it was also sometimes known as ArgumentDo or occasionaly ArgumentBody.
In standard Haskell 2010, some expressions cannot be used as arguments to functions without parentheses or, perhaps more idiomatically, a dollar sign between the function and its argument.The expressions under discussion can be used as arguments to operators without parentheses or the dollar sign. Consider the difference between
fmap (+1) (Just 3) and
(+1) <$> Just 3. In the first case, the parentheses are necessary around
Just 3, although this is an acceptable substitute:
fmap (+1) $ Just 3. In either case, we use some punctuation to give the parser a little help. But with the infix operators, the precedence and fixity rules often obviate the need for it. These include
do blocks and
mdo blocks enabled by the
if-then-else expressions; lambda expressions;
let expressions; and the
\case expressions enabled by
LambdaCase. But Haskellers will do nearly anything to avoid using parentheses, so now we have a syntactic extension that allows these expressions to be parsed directly, without parentheses or
$, as arguments to the function.
It is worth noting before we move on to examples that ambiguities arising from use of this extension are resolved by reading the expression as extending as far to the right as possible. Thus,
f \a -> a b will be parsed as
f (\a -> a b), not as
f (\a -> a) b.
BlockArguments GHC User Guide documentation.
This is the most typical use case for this extension, because using a
do block as an argument to a function is so common.
Consider a typical usage of
forever with a
do block argument:
BlockArguments extension enabled, it can now be written:
What will you do with all your extra dollars now that you no longer need them for this?
If you remove the
$ but forget to enable the extension, the compiler will helpfully remind you that that’s probably what you were trying to do:
error: Unexpected do block in function application: do word <- fmap fixString getLine isPalindrome word You could write it with parentheses Or perhaps you meant to enable BlockArguments? | 25 | do | ^^...
The extension permits multiple block arguments as well.This example is fun in the REPL. To open a REPL that will run it, try
stack repl --package async --resolver nightly. Concurrency is fun.
As we noted above, this extension works with some other expressions. We’ll look next at how you could use it with the example we give on the
BlockArguments allows you to get rid of those parentheses. Unfortunately, it does not relieve you of the need to indent your cases properly!