RosettaCodeData/Task/ABC-Problem/JavaScript/abc-problem-5.js

98 lines
2.9 KiB
JavaScript

(() => {
'use strict';
// ABC BLOCKS -------------------------------------------------------------
// spellWith :: [(Char, Char)] -> [Char] -> [[(Char, Char)]]
const spellWith = (blocks, wordChars) =>
(isNull(wordChars)) ? [
[]
] :
(() => {
const [x, xs] = uncons(wordChars);
return concatMap(
b => elem(x, b) ? concatMap(
bs => [cons(b, bs)],
spellWith(
deleteBy(
(p, q) => (p[0] === q[0]) && (p[1] === q[1]),
b, blocks
),
xs
)
) : [],
blocks
);
})();
// GENERIC FUNCTIONS ------------------------------------------------------
// compose :: [(a -> a)] -> (a -> a)
const compose = fs => x => fs.reduceRight((a, f) => f(a), x);
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) => [].concat.apply([], xs.map(f));
// cons :: a -> [a] -> [a]
const cons = (x, xs) => [x].concat(xs);
// curry :: Function -> Function
const curry = (f, ...args) => {
const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :
function () {
return go(xs.concat([].slice.apply(arguments)));
};
return go([].slice.call(args, 1));
};
// deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]
const deleteBy = (f, x, xs) =>
xs.length > 0 ? (
f(x, xs[0]) ? (
xs.slice(1)
) : [xs[0]].concat(deleteBy(f, x, xs.slice(1)))
) : [];
// elem :: Eq a => a -> [a] -> Bool
const elem = (x, xs) => xs.indexOf(x) !== -1;
// isNull :: [a] -> Bool
const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined;
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// not :: Bool -> Bool
const not = b => !b;
// show :: a -> String
const show = x => JSON.stringify(x); //, null, 2);
// stringChars :: String -> [Char]
const stringChars = s => s.split('');
// toUpper :: Text -> Text
const toUpper = s => s.toUpperCase();
// uncons :: [a] -> Maybe (a, [a])
const uncons = xs => xs.length ? [xs[0], xs.slice(1)] : undefined;
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// words :: String -> [String]
const words = s => s.split(/\s+/);
// TEST -------------------------------------------------------------------
// blocks :: [(Char, Char)]
const blocks = words(
"BO XK DQ CP NA GT RE TG QD FS JW HU VI AN OB ER FS LY PC ZM"
);
return unlines(map(
x => show([x, compose(
[not, isNull, curry(spellWith)(blocks), stringChars, toUpper]
)(x)]), ["", "A", "BARK", "BoOK", "TrEAT", "COmMoN", "SQUAD", "conFUsE"]
));
})();