Open koraa opened 3 years ago
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.
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.
*vanilla – as in no transpilers or compilers involved