Last active
November 6, 2019 00:01
-
-
Save MarkusPfundstein/49ed6c91e66fce4e6873b651bc7aaf11 to your computer and use it in GitHub Desktop.
pattern matching function using ramda
This file contains 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
/* | |
* 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