6.2.17. More liberal syntax for function arguments — Glasgow Haskell Compiler 9.10.0.20240413 User's Guide

# 6.2.17. More liberal syntax for function arguments

`BlockArguments`

  Since: | 8.6.1

  Allow `do` expressions, lambda expressions, etc. to be directly used as a function argument.

In Haskell 2010, certain kinds of expressions can be used without parentheses as an argument to an operator, but not as an argument to a function. They include `do`, lambda, `if`, `case`, and `let` expressions. Some GHC extensions also define language constructs of this type: `mdo` (The recursive do-notation), `\case` (Lambda-case), and `proc` (Arrow notation).

The `BlockArguments` extension allows these constructs to be directly used as a function argument. For example:

    when (x > 0) do
      print x
      exitFailure

will be parsed as:

    when (x > 0) (do
      print x
      exitFailure)

and

    withForeignPtr fptr \ptr -> c_memcpy buf ptr size

will be parsed as:

    withForeignPtr fptr (\ptr -> c_memcpy buf ptr size)

## 6.2.17.1. Changes to the grammar

The Haskell report defines the `lexp` nonterminal thus (`*` indicates a rule of interest)

    lexp  →  \ apat1 … apatn -> exp            (lambda abstraction, n ≥ 1)  *
          |  let decls in exp                  (let expression)             *
          |  if exp [;] then exp [;] else exp  (conditional)                *
          |  case exp of { alts }              (case expression)            *
          |  do { stmts }                      (do expression)              *
          |  fexp

    fexp  →  [fexp] aexp                       (function application)

    aexp  →  qvar                              (variable)
          |  gcon                              (general constructor)
          |  literal
          |  ( exp )                           (parenthesized expression)
          |  qcon { fbind1 … fbindn }          (labeled construction)
          |  aexp { fbind1 … fbindn }          (labelled update)
          |  …

The `BlockArguments` extension moves these production rules under `aexp`

    lexp  →  fexp

    fexp  →  [fexp] aexp                       (function application)

    aexp  →  qvar                              (variable)
          |  gcon                              (general constructor)
          |  literal
          |  ( exp )                           (parenthesized expression)
          |  qcon { fbind1 … fbindn }          (labeled construction)
          |  aexp { fbind1 … fbindn }          (labelled update)
          |  \ apat1 … apatn -> exp            (lambda abstraction, n ≥ 1)  *
          |  let decls in exp                  (let expression)             *
          |  if exp [;] then exp [;] else exp  (conditional)                *
          |  case exp of { alts }              (case expression)            *
          |  do { stmts }                      (do expression)              *
          |  …

Now the `lexp` nonterminal is redundant and can be dropped from the grammar.

Note that this change relies on an existing meta-rule to resolve ambiguities:

> 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.

For example, `f \a -> a b` will be parsed as `f (\a -> a b)`, not as `f (\a -> a) b`.