Skip to content

Instantly share code, notes, and snippets.

@tabatkins
Last active Jan 31, 2022
Embed
What would you like to do?
ADT, Decorators, Pattern Matching
// This is a decorated version of <https://github.com/tc39/proposal-pattern-matching#custom-matcher-protocol-interpolations>
// A predefined ADT decorator.
// Use it on static "constructor" methods only.
// Pass an extractor function, to produce a pattern-matching value.
// The instance must have an [ADT.kind] property
// set to the constructor method used.
const ADT = (valExtractor=()=>null) => (_, {methodName, isStatic, kind, addInitializer}) => {
if(kind == "method" && isStatic) {
addInitializer(function(){
// `this` is the class
const cls = this;
const method = cls[methodName];
method[Symbol.matcher] = (matchable) => {
if(matchable instanceof cls && matchable[ADT.kind] == method) {
return {matched: true, value:valExtractor(matchable)};
}
return {matched:false};
}
});
} else {
throw new Exception("only usable on static methods");
}
}
ADT.kind = new Symbol("ADT kind");
class Option {
constructor(kind, val) {
this[ADT.kind] = kind;
if(this[ADT.kind] == Option.Some) {
this._value = val;
}
}
get value() {
if(this.isSome()) return this._value;
throw new Exception("Can't get the value of an Option.None.");
}
get isSome() {
return this[ADT.kind] == Option.Some;
}
@ADT(x=>x.value)
static Some(val) {
return new Option(Option.Some, val);
}
@ADT()
static None() {
return new Option(Option.None);
}
}
match(result) {
when (${Option.Some} with val) -> console.log(val);
when (${Option.None}) -> console.log("none");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment