summaryrefslogtreecommitdiff
path: root/docs/users_guide/exts/block_arguments.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/users_guide/exts/block_arguments.rst')
-rw-r--r--docs/users_guide/exts/block_arguments.rst103
1 files changed, 103 insertions, 0 deletions
diff --git a/docs/users_guide/exts/block_arguments.rst b/docs/users_guide/exts/block_arguments.rst
new file mode 100644
index 0000000000..1682ddac5b
--- /dev/null
+++ b/docs/users_guide/exts/block_arguments.rst
@@ -0,0 +1,103 @@
+.. _block-arguments:
+
+More liberal syntax for function arguments
+------------------------------------------
+
+.. extension:: BlockArguments
+ :shortdesc: Allow ``do`` blocks and other constructs as function arguments.
+
+ :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`` (:ref:`recursive-do-notation`), ``\case`` (:ref:`lambda-case`), and
+``proc`` (:ref:`arrow-notation`).
+
+The :extension:`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)
+
+Changes to the grammar
+~~~~~~~~~~~~~~~~~~~~~~
+
+The Haskell report `defines
+<https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-220003>`_
+the ``lexp`` nonterminal thus (``*`` indicates a rule of interest)
+
+.. code-block:: none
+
+ 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 :extension:`BlockArguments` extension moves these production rules under
+``aexp``
+
+.. code-block:: none
+
+ 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``.
+
+