-
-
Save logarytm/5687e90624f91dbee7e523d82c823f00 to your computer and use it in GitHub Desktop.
dirty pattern matching in pure JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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