Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended pattern matching #182

Open
evincarofautumn opened this issue Jun 19, 2017 · 0 comments
Open

Extended pattern matching #182

evincarofautumn opened this issue Jun 19, 2017 · 0 comments

Comments

@evincarofautumn
Copy link
Owner

As a simple extension to the current pattern matching facility, I’d like to allow match on literals, since they’re essentially the “constructors” of intrinsic types:

define fib (UInt32 -> UInt32):
  -> n;
  match (n)
  case 0u32:
    1u32
  case 1u32:
    1u32
  else:
    (n - 1u32) fib + (n - 2u32) fib

match (some_char)
case 'a':
  ayy
case 'z':
  zzz
else:
  wat

For better usability, pattern matching needs to be extended to support more than just constructors. I have a rough idea of what it ought to look like, but haven’t worked out all the semantics.

Matching on List would be a good first step. Examples:

  • case []: empty list
  • case [...]: any list
  • case [_]: any list of length 1
  • case [_, _, _]: any list of length 3
  • case [a, _]: any list of length 1, binding a
  • case [a, ...]: any list of length 1 or greater, binding the first element
  • case [..., a]: any list of length 1 or greater, binding the last element
  • case [0, ..., 1]: any list of length 2 or greater, beginning with 0 and ending with 1
  • case [1, ..., ...]: error, adjacent ...
  • case [1, ..., 2, ..., 3]: error, patterns between ...
  • case [_, ...]: any list of length 1 or greater
  • case "abc": sugar for case ['a', 'b', 'c']

For other constructors, I think it makes sense to require parentheses and write them in postfix like constructor application. The last word in a parenthesised pattern is the constructor.

match (optional_int)
case (n some): n
case none: 0

As for lists, ... could be used to ignore multiple adjacent fields.

type Triple<A, B, C> { case triple (A, B, C) }

define third<A, B, C> (Triple<A, B, C> -> C):
  match (1 2 3 triple)
  case (... x triple): x

The as keyword could be reused to bind the result of a pattern match to a name, like Haskell’s @ (“as-patterns”) or OCaml’s as.

define dup_head<T> (List<T> -> List<T>):
  match
  case [x, ...] as xs:
    x xs prepend
  case []:
    []

type Rational<T>:
  case rat (T, T)

define min_rational (Rational<Int32>, Rational<Int32> -> Rational<Int32>)
  pair match
  case ((_ 0 rat) r2 pair): r2
  case (r1 (_ 0 rat) pair): r1
  case (((n1 d1 rat) as r1) ((n2 d2 rat) as r2) pair):
    if (n1 * d2 < n2 * d1):
      r1
    else:
      r2

Guards could reuse the if keyword; a case could accept an if/elif/else expression as a body, and fall through to the next pattern if no condition matched. Unfortunately this is ambiguous with else as used in match, so maybe it needs to be written as case else or something.

define something_positive (Optional<Int32> -> Optional<Int32>):
  -> x;
  match (x)
  case (n some) if (n < 0):
    n neg some
  else:
    x

Exhaustiveness checking also becomes much more involved with more complex patterns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant