This page is a summary of proposals from #4359
The problem
The current lambda abstraction syntax allows us to conveniently bind parts of the arguments by using patterns, but does not provide a way to branch quickly (without naming the argument). Usually we just cringe a bit and write
\tmp -> case tmp of
Pat1 -> ...
Pat2 -> ...
or even
\meaningfulName -> case meaningfulName of
Pat1 -> ...
Pat2 -> ...
However, when this situation nests (e.g. monadic bind) and variables have the same type, naming becomes painful and often degrades to not-so-meaningful meaningfulName1
, meaningfulName2
, ...
A similar problem exists with proc
expressions from arrow notation, which can be regarded as generalized lambda expressions. We sometimes have expressions of the following structure:
proc meaningfulName -> case meaningfulName of
Pat1 -> ...
Pat2 -> ...
Here, the dots stand for arrow expressions, not ordinary expressions.
The proposals
case of
LambdaCase: A simple sugar for one-argument lambda abstractions.
case of
Pat1 -> Expr1
Pat2 -> Expr2
desugars to
\freshName -> case freshName of
Pat1 -> Expr1
Pat2 -> Expr2
-
Pros
- No conflicts with the current syntax (the sequence
case of
is illegal)
- No conflicts with the current syntax (the sequence
-
Cons
- Looks weird (no hint of being a lambda abstraction)
- Single-argument solution (see the note)
- Cannot be generalized to cover also
proc
expressions
\case
LambdaCase: A "less weird" version of case of
. As above,
\case
Pat1 -> Expr1
Pat2 -> Expr2
desugars to
\freshName -> case freshName of
Pat1 -> Expr1
Pat2 -> Expr2
(\case
is a layout herald).
-
Pros
- No conflicts with the current syntax (the sequence
\ case
is illegal) - An analog syntax for
proc
expressions can be gained by replacing\
withproc
- No conflicts with the current syntax (the sequence
-
Cons
-
Single-argument solution (see the note). One way to extend it to support multiple arguments is
\case Pat1_1, Pat1_2, ... -> Expr1 Pat2_1, Pat2_2, ... -> Expr2
(separation with commas is supposed to preserve case-like feel, e.g.
Just x, Just y ->
vs(Just x) (Just y) ->
) which is considered unorthodox by GHC HQ.
-
MultiClauseLambdas
Extend the current syntax with alternative clauses:
\Pat1_1 Pat1_2 ... -> Expr1
Pat2_1 Pat2_2 ... -> Expr2
...
(\
becomes a layout herald)
-
Pros
- Multi-argument solution (see the note)
- An analog syntax for
proc
expressions can be gained by replacing\
withproc
-
Cons
-
Breaks current idioms. For example,
mask $ \restore -> do stmt1 stmt2
becomes illegal because
stmt1
is indented less thanrestore
. One way to avoid this is to not make\
a herald, forcing users to use explicit layout for multi-clause abstractions, i.e.\ { Pat1_1 Pat1_2 ... -> Expr1 ; Pat2_1 Pat2_2 ... -> Expr2 }
Another is to start each clause with a
\
:\ Pat1_1 Pat1_2 ... -> Expr1 \ Pat2_1 Pat2_2 ... -> Expr2 \ ...
-
MultiClauseLambdas with a keyword
Addresses the layout problem of MultiClauseLambdas. Requires multi-clause abstractions to have a keyword after \
:
\KEYWORD Pat1_1 Pat1_2 ... -> Expr1
Pat2_1 Pat2_2 ... -> Expr2
...
(\KEYWORD
is a layout herald)
-
Pros
- No conflicts with the current syntax
- Multi-argument solution (see the note)
- An analog syntax for
proc
expressions can be gained by replacing\
withproc
-
Cons
- Deciding on the keyword may take years
Extra: LambdaMatch
A full revamp of pattern matching: Haskell' ticket.
Notes
Single vs multi-argument
(field report by Mikhail Vorozhtsov) I've been using \case
for over a year and tried MultiClauseLambdas for about two months. In my code base \case
seems to cover 99% of cases (no pun intended) and curry $ \case ...
does the job for the rest, so having only a single-argument solution may be not as restrictive as it seems. On the other hand, I had a hard time with MultiClauseLambdas extra clauses: I just kept writing Just x -> Expr
instead of the correct (Just x) -> Expr
. It seems that lines like [spaces]Pat -> Expr
are just hardwired to case-expressions in my brain.