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,251
    • Issues 4,251
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
    • Iterations
  • Merge Requests 395
    • Merge Requests 395
  • Requirements
    • Requirements
    • List
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
  • Security & Compliance
    • Security & Compliance
    • Dependency List
    • License Compliance
  • Operations
    • Operations
    • Incidents
    • Environments
  • Analytics
    • Analytics
    • CI / CD
    • Code Review
    • Insights
    • Issue
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • Glasgow Haskell Compiler
  • GHCGHC
  • Wiki
  • lambdas vs pattern matching

Last edited by Ben Gamari Apr 01, 2019
Page history New page

lambdas vs pattern matching

This page is a summary of proposals from #4359 (closed)

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

GHC Home
GHC User's Guide

Joining In

Newcomers info
Mailing Lists & IRC
The GHC Team

Documentation

GHC Status Info
Working conventions
Building Guide
Debugging
Commentary

Wiki

Title Index
Recent Changes