Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
GHC
GHC
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,385
    • Issues 4,385
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 370
    • Merge Requests 370
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Wiki
  • lambdas vs pattern matching

Last edited by Ben Gamari Apr 01, 2019
Page history New page
This is an old version of this page. You can view the most recent version or browse the history.

lambdas vs pattern matching

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.

Clone repository Edit sidebar
  • All things layout
  • AndreasK
  • AndreasPK
  • Building GHC on Windows with Stack protector support (SSP) (using Make)
  • CAFs
  • CafInfo rework
  • Compiling Data.Aeson Error
  • Contributing a Patch
  • Core interface section
  • Dead Code
  • Developing Hadrian
  • Documentation Style Guide
  • Doubleton Arrays
  • Errors as (structured) values
  • Extensible Interface Files
View All Pages