Skip to content

Instantly share code, notes, and snippets.

@logarytm
Last active January 7, 2018 21:42
Show Gist options
  • Save logarytm/5687e90624f91dbee7e523d82c823f00 to your computer and use it in GitHub Desktop.
Save logarytm/5687e90624f91dbee7e523d82c823f00 to your computer and use it in GitHub Desktop.
dirty pattern matching in pure JavaScript
function match(value) {
const branches = [];
let otherwiseBranch = (value) => {
// TODO better message
throw new Error(`${value} not matched`);
};
const publicApi = { get, when, otherwise };
function get() {
for (let b of branches) {
if (b.test(value)) {
return b.f(value);
}
}
return otherwiseBranch(value);
}
function adaptTest(test) {
if (typeof test === 'function') {
return test;
} else if (typeof test === 'object') {
if (test === null) {
return match.equal(null);
}
const pattern = test;
return (value) => {
if (typeof value !== 'object' || value === null) {
return false;
}
return Object.keys(pattern).every((key) => {
return adaptTest(pattern[key])(value[key]);
});
};
}
return match.equal(test);
}
function when(test, f) {
branches.push({ test: adaptTest(test), f });
return publicApi;
}
function otherwise(f) {
otherwiseBranch = f;
return publicApi;
}
return publicApi;
}
const M = match;
M.equal = function equal(expectedValue) {
return (value) => {
// TODO: handle shit correctly
try {
require('assert').deepStrictEqual(value, expectedValue);
return true;
} catch (error) {
return false;
}
};
};
M.number = function number(value) {
return typeof value === 'number';
};
M.func = function func() {
return typeof value === 'function';
};
M.any = function any(type) {
return () => true;
};
const f = (value) => match(value)
.when(M.number, (value) => -value)
.when({ x: M.number, y: M.number }, ({ x, y }) => {
return `{x:${x}, y:${y}}`;
})
.when([M.number, M.number], ([x, y]) => {
return `[${x}, ${y}]`;
})
.when(null, () => 'Nothing')
.otherwise(() => '???')
.get();
console.log(f({ x: 123, y: 456 }));
console.log(f([123, 456]));
console.log(f(123));
console.log(f(null));
console.log(f(undefined));
/* Result:
{x:123, y:456}
[123, 456]
-123
Nothing
???
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment