unison/unison-src/transcripts/lambdacase.output.md
Greg Pfeil 0031542faf
Add a space before code block info strings
This is for consistency with the `cmark` style. Now the blocks we still
pretty-print ourselves will match the bulk of them that `cmark`
produces.
2024-07-10 13:56:07 -06:00

5.0 KiB

Lambda case syntax

This function takes a single argument and immediately pattern matches on it. As we'll see below, it can be written using cases syntax:

isEmpty x = match x with
  [] -> true
  _ -> false

  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      isEmpty : [t] -> Boolean

Here's the same function written using cases syntax:

isEmpty2 = cases
  [] -> true
  _ -> false

  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      isEmpty2 : [t] -> Boolean
        (also named isEmpty)

Notice that Unison detects this as an alias of isEmpty, and if we view isEmpty

scratch/main> view isEmpty

  isEmpty : [t] -> Boolean
  isEmpty = cases
    [] -> true
    _  -> false

it shows the definition using cases syntax opportunistically, even though the code was originally written without that syntax.

Multi-argument cases

Functions that take multiple arguments and immediately match on a tuple of arguments can also be rewritten to use cases. Here's a version using regular match syntax on a tuple:

merge : [a] -> [a] -> [a]
merge xs ys = match (xs, ys) with
  ([], ys) -> ys
  (xs, []) -> xs
  (h +: t, h2 +: t2) ->
    if h <= h2 then h  +: merge t (h2 +: t2)
    else            h2 +: merge (h +: t) t2
scratch/main> add

  ⍟ I've added these definitions:
  
    merge : [a] -> [a] -> [a]

And here's a version using cases. The patterns are separated by commas:

merge2 : [a] -> [a] -> [a]
merge2 = cases
  [], ys -> ys
  xs, [] -> xs
  h +: t, h2 +: t2 ->
    if h <= h2 then h  +: merge2 t (h2 +: t2)
    else            h2 +: merge2 (h +: t) t2

  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      merge2 : [a] -> [a] -> [a]
        (also named merge)

Notice that Unison detects this as an alias of merge, and if we view merge

scratch/main> view merge

  merge : [a] -> [a] -> [a]
  merge = cases
    [], ys -> ys
    xs, [] -> xs
    h +: t, h2 +: t2 ->
      if h <= h2 then h +: merge t (h2 +: t2)
      else h2 +: merge (h +: t) t2

it again shows the definition using the multi-argument cases syntax opportunistically, even though the code was originally written without that syntax.

Here's another example:

structural type B = T | F

blah : B -> B -> Text
blah = cases
  T, x -> "hi"
  x, y -> "bye"

blorf = cases
  x, T -> x
  x, y -> y

> blah T F
> blah F F
> blorf T F

  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      structural type B
      blah  : B -> B -> Text
      blorf : B -> B -> B
  
  Now evaluating any watch expressions (lines starting with
  `>`)... Ctrl+C cancels.

    12 | > blah T F
           ⧩
           "hi"
  
    13 | > blah F F
           ⧩
           "bye"
  
    14 | > blorf T F
           ⧩
           F

Patterns with multiple guards

merge3 : [a] -> [a] -> [a]
merge3 = cases
  [], ys -> ys
  xs, [] -> xs
  h +: t, h2 +: t2 | h <= h2   -> h  +: merge3 t (h2 +: t2)
                   | otherwise -> h2 +: merge3 (h +: t) t2

  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      merge3 : [a] -> [a] -> [a]

scratch/main> add

  ⍟ I've added these definitions:
  
    merge3 : [a] -> [a] -> [a]

scratch/main> view merge3

  merge3 : [a] -> [a] -> [a]
  merge3 = cases
    [], ys           -> ys
    xs, []           -> xs
    h +: t, h2 +: t2 
      | h <= h2   -> h +: merge3 t (h2 +: t2)
      | otherwise -> h2 +: merge3 (h +: t) t2

This is the same definition written with multiple patterns and not using the cases syntax; notice it is considered an alias of merge3 above.

merge4 : [a] -> [a] -> [a]
merge4 a b = match (a,b) with
  [], ys -> ys
  xs, [] -> xs
  h +: t, h2 +: t2 | h <= h2   -> h  +: merge4 t (h2 +: t2)
  h +: t, h2 +: t2 | otherwise -> h2 +: merge4 (h +: t) t2

  Loading changes detected in scratch.u.

  I found and typechecked these definitions in scratch.u. If you
  do an `add` or `update`, here's how your codebase would
  change:
  
    ⍟ These new definitions are ok to `add`:
    
      merge4 : [a] -> [a] -> [a]
        (also named merge3)