64 lines
1.7 KiB
JavaScript
64 lines
1.7 KiB
JavaScript
(() => {
|
|
"use strict";
|
|
|
|
// -- INSTANCE-SPECIFIC CHARACTER REPLACEMENT RULES --
|
|
|
|
// # nthInstanceReplaced :: Dict Char [(Null | Char)] ->
|
|
const nthInstanceReplaced = ruleMap =>
|
|
// A string defined by replacements specified for
|
|
// the nth instances of various characters.
|
|
s => mapAccumL(
|
|
(a, c) => c in a ? (() => {
|
|
const ds = a[c];
|
|
|
|
return Boolean(ds.length) ? [
|
|
Object.assign(a, {[c]: ds.slice(1)}),
|
|
ds[0] || c
|
|
] : [a, c];
|
|
})() : [a, c]
|
|
)(Object.assign({}, ruleMap))(
|
|
[...s]
|
|
)[1].join("");
|
|
|
|
|
|
// ---------------------- TEST -----------------------
|
|
const main = () =>
|
|
// Instance-specific character replacement rules.
|
|
nthInstanceReplaced({
|
|
a: ["A", "B", null, "C", "D"],
|
|
b: ["E"],
|
|
r: [null, "F"]
|
|
})(
|
|
"abracadabra"
|
|
);
|
|
|
|
|
|
// --------------------- GENERIC ---------------------
|
|
|
|
// mapAccumL :: (acc -> x -> (acc, y)) -> acc ->
|
|
// [x] -> (acc, [y])
|
|
const mapAccumL = f =>
|
|
// A tuple of an accumulation and a list
|
|
// obtained by a combined map and fold,
|
|
// with accumulation from left to right.
|
|
acc => xs => [...xs].reduce(
|
|
([a, bs], x) => second(
|
|
v => [...bs, v]
|
|
)(
|
|
f(a, x)
|
|
),
|
|
[acc, []]
|
|
);
|
|
|
|
|
|
// second :: (a -> b) -> ((c, a) -> (c, b))
|
|
const second = f =>
|
|
// A function over a simple value lifted
|
|
// to a function over a tuple.
|
|
// f (a, b) -> (a, f(b))
|
|
([x, y]) => [x, f(y)];
|
|
|
|
|
|
// MAIN --
|
|
return main();
|
|
})();
|