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

Compex pattern matching #135

Open
koraa opened this issue Oct 23, 2020 · 1 comment
Open

Compex pattern matching #135

koraa opened this issue Oct 23, 2020 · 1 comment
Labels
enhancement New feature or request needs-api-design question Further information is requested

Comments

@koraa
Copy link
Contributor

koraa commented Oct 23, 2020

Is it possible to find a construction for advanced pattern matching including type signatures in vanilla* js?

The following construction doesn't seem very sound to me, but maybe we can come up with something.

// Turns numbers into strings, strings into numbers, and throws errors for anything else
patternMatch(
  is_a(String),    Number,
  is_a(Number), String,
  yes,                 identity);
tryPatternMatch(
  is_a(String),    Number,
  is_a(Number), String);

exec(Y(rematch => patternMatch(
  is_any([String, Number]), (v) => rematch([v]),
  is_a(Array), map(x => Number(x)*2 + 1),
)));

*vanilla – as in no transpilers or compilers involved

@koraa koraa added the enhancement New feature or request label Oct 23, 2020
@koraa koraa added needs-api-design question Further information is requested labels Apr 30, 2021
@koraa
Copy link
Contributor Author

koraa commented May 11, 2021

Update: We might be able to model this as a trait:

const PatternMatching = Trait("PatternMatching");
// Implementation for primitives: by identity
// Implementation for arrays, objects, etc: By recursion
// Implementation for regex: As group match

const tryMatch = (targ, default, pattern) =>
  ifdef(patternMatching.invoke(pattern, targ), (m) => Object.assign([], m));

const match = (targ, pattern) => {
  const None = Symbol();
  const m = tryMatch(targ, None, pattern);
  if (m === None) throw MatchFailed(/* … */);
  rerturn m;
};

const AnyMatcher = Tuple('any', [], {
  [PatternMatching.sym](value, matches) {
    matches.push(value);
  }
});

const any = AnyMatcher.new();
const any_as = NamedAnyMatcher.new;

const group = (name, pattern) =>  // produces an entire subgroup match
const as = (name, pattern) =>  // just binds the name
const when = (predicate) =>  // Just executes the predicate

const anyof = (patterns) =>  // allows multiple patterns
const allof  = (patterns) =>  // requires multiple patterns to match

const exact = (value) =>  // match by identity
const equality = (value) =>  // match anything that equals the given predicate

const subtype = (value) =>
const type = (value) =>
const classy = (type, records) =>

const if_else_match = (targ, default, pattern, fn) => {
  const None = Symbol();
  const m = tryMatch(targ, None, pattern);
  return m === None ? default : fn(m);
};

const if_match = (targ, pattern, fn) => if_else_match(targ, undefined, pattern, fn);

const match_on = (value, patterns…) => 

const fibonacci = (x) => match_on(x,
  match(0, _ => 0),
  match(1, _ => 1),
  match(any, (_) => fibonacci(x-1) + fibonacci(x-2)
);

// Complex example

const Add = Tuple('Add', ['a', 'b']);
const Mul = Tuple("Mul", ['a', 'b']);
const calc = (tree) => match_on(tree,
  match(Add(any, any), ([a, b]) => a+b),
  match(Mul(any, any), ([a, b]) => a*b),
  match(Number, (x) => x,
  /* throws */);
calc(2) // 2
calc(Mul(Add(2, 3), 4)) // 20

This basically models matching as a trait where the implementation is given the object to be matched; if the object matches successfully, the implementation returns an array that may contain number and string keys matched otherwise undefined is returned. Some standard types such as Object, Array, etc and Primitive types are implemented by default. Containers recurse and primitive types compare by identity. RegExps are integrated into matching. This probably needs to be extended to support customizers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request needs-api-design question Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant