Skip to content

Instantly share code, notes, and snippets.

@MarkusPfundstein
Last active November 6, 2019 00:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarkusPfundstein/49ed6c91e66fce4e6873b651bc7aaf11 to your computer and use it in GitHub Desktop.
Save MarkusPfundstein/49ed6c91e66fce4e6873b651bc7aaf11 to your computer and use it in GitHub Desktop.
pattern matching function using ramda
/*
* examples - code for matchC is below
* to test: copy&paste into http://ramdajs.com/repl
*/
function main() {
// its all good if all output lines have true in first tuple ;-)
const m1 = matchC('Hello')
.when('string', a => [true, a.toUpperCase()])
.when('number', a => [false, a])
.otherwise(_ => [false, 'no match'])
L(m1);
const m2 = matchC(['Hello', 5])
.when(['string', 'string'], ([a, b]) => [false, a, b])
.when(['string', 'number'], ([a, b]) => [true, a, b])
.otherwise(_ => [false, 'no match'])
L(m2);
const m3 = matchC(['Hello', 5, 100])
.when(['string', 'string'], (a, b) => [false, a, b])
.when(['string', 'number', 'string'], ([a, b, c]) => [false, a, b, c])
.when(['string', 'string', 'string'], ([a, b, c]) => [false, a, b, c])
.when(['string', 'number', 'number'], ([a, b, c]) => [true, a, b, c])
.otherwise(_ => [false, 'no match'])
L(m3);
const m4 = matchC(['Hello', [5, 100], 100])
.when(['string', 'string'], (a, b) => [false, a, b])
.when(['string', 'number', 'string'], ([a, b, c]) => [false, a, b, c])
.when(['string', 'string', 'string'], ([a, b, c]) => [false, a, b, c])
.when(['string', 'number', 'number'], ([a, b, c]) => [false, a, b, c])
.when(['string', ['number', 'number'], 'string'], ([a, b, c]) => [false, a, b, c])
.otherwise(_ => [true, 'no match'])
L(m4);
const m5 = matchC(['Hello', [100, 100], 100])
.when(['Hello', [5, 5], '_'], ([a, b, c]) => [false, a, b, c])
.when(['Hello', [100, 100], p => p < 100], ([a, b, c]) => [false, a, b, c])
.when(['Goodbye', ['_', '_'], '_'], ([a, b, c]) => [false, a, b, c])
.when(['_', [100, 100], p => p === 100], ([a, b, c]) => [true, a, b, c])
.otherwise(_ => [false, 'no match'])
L(m5);
class ABox {
constructor(v) {
this.v = v;
}
}
const m6 = matchC([new ABox(5), [new ABox(10), new ABox(20)]])
.when([ABox, 5], ([a, b]) => [false, a, b])
.when([ABox, [ABox, ABox]], ([a, b]) => [true, a, b])
.otherwise(_ => 'no match');
L(m6);
}
/*
* matchC code
*/
const L = console.log;
const safeInstanceOf = (t, tc) => {
try {
return t instanceof tc;
} catch (_) {
return false;
}
}
const safeCall = (f, t) => {
try {
return f(t);
} catch (e) {
return false;
}
};
const _matchP = function(type, tc) {
//L(`type: ${type}, tc: ${tc}`);
if (tc === '_' || tc === type) {
return true;
} else if (Array.isArray(tc) && Array.isArray(type) && tc.length === type.length) {
return R.all(p => _matchP(p[1], p[0]), R.zip(tc, type));
} else if (typeof type === tc || safeInstanceOf(type, tc)) {
return true;
} else if (typeof tc === 'function' && safeCall(tc, type) === true) {
return true;
} else {
return false;
}
}
const _matchC = function(type, hasType = false) {
const when = (tc, f) => {
if (hasType) {
return _matchC(type, true);
}
if (_matchP(type, tc)) {
return _matchC(f(type), true);
} else {
return _matchC(type, false);
}
};
const otherwise = (f) => {
if (hasType) {
return type;
}
return f(type);
}
return { when, otherwise };
}
const matchC = (t) => _matchC(t);
const assert = (p, text) => {
if (p === false) {
throw new Error(text);
}
}
/*
* run examples
*/
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment