Skip to content

Instantly share code, notes, and snippets.

@tabatkins
Last active January 31, 2022 22:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tabatkins/d974137e9ab0272acb3e57cccde99300 to your computer and use it in GitHub Desktop.
Save tabatkins/d974137e9ab0272acb3e57cccde99300 to your computer and use it in GitHub Desktop.
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