wiki:LambdasVsPatternMatching

Version 3 (modified by mikhail.vorozhtsov, 22 months ago) (diff)

Added MultiClauseLambdas? with \ in each clause

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

LambdaCase: case of

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)
  • Cons
    • Looks weird (no hint of being a lambda abstraction)
    • Single-argument solution (see the note)
    • Cannot be generalized to cover also proc expressions

LambdaCase: \case

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 \ with proc
  • 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 \ with proc
  • Cons
    • Breaks current idioms. For example,
      mask $ \restore -> do
        stmt1
        stmt2
      
      becomes illegal because stmt1 is indented less than restore. 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 \ with proc
  • 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.