Skip to content

Instantly share code, notes, and snippets.

@zkbpkp
Last active August 20, 2017 18:45
Show Gist options
  • Save zkbpkp/9684e99239beca35dd2ed27e6e5104de to your computer and use it in GitHub Desktop.
Save zkbpkp/9684e99239beca35dd2ed27e6e5104de to your computer and use it in GitHub Desktop.
const tag = Symbol();
const data = (variants, extend = class {}) => {
const obj = class extends extend {};
for (const v in variants) {
let cargs;
obj[v] = (...args) => new (class extends obj {
constructor(...args) {
super();
cargs = args;
this[tag] = v;
for (let i = 0, len = args.length; i < len; ++i) {
this[variants[v][i]] = args[i];
}
}
match(cases) {
for (const c in cases) {
if (c === this[tag]) {
return cases[c](this);
}
}
}
toString() {
return `${v}(${cargs.join(', ')})`;
}
})(...args);
}
return obj;
};
/* Example with prototype inheritance */
const Maybe = data(
{
Just: ['value'],
Nothing: null
},
class {
bind(fn) {
return this.match({
Just: ({ value }) => fn(value),
Nothing: () => this
});
}
}
);
Maybe.Just(4).bind(x => Maybe.Just(x * x)); // => Some(16)
Maybe.None().bind(x => Maybe.Just(x)); // => None()
/* Example without prototype inheritance */
const Option = data({
Some: ['value'],
None: [],
});
const bind = f => m => m.match({
Some: ({ value }) => f(value),
None: () => m,
});
bind(x => Option.Some(x * x))(Option.Some(4)); // => Some(16)
bind(x => Option.Some(x))(Option.None()); // => None()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment