RosettaCodeData/Task/Sierpinski-triangle/JavaScript/sierpinski-triangle-4.js

63 lines
1.9 KiB
JavaScript

(() => {
'use strict';
// LINES OF SIERPINSKI TRIANGLE AT LEVEL N -------------------------------
// sierpinski :: Int -> [String]
const sierpTriangle = n =>
// Previous triangle centered with left and right padding,
(n > 0) ? concat(ap([
map(xs => intercalate(xs, ap(
[s => concat(replicate(Math.pow(2, (n - 1)), s))], [' ', '-']
))),
// above a pair of duplicates, placed one character apart.
map(xs => intercalate('+', [xs, xs]))
], [sierpTriangle(n - 1)])) : ['▲'];
// GENERIC FUNCTIONS -----------------------------------------------------
// replicate :: Int -> a -> [a]
const replicate = (n, a) => {
let v = [a],
o = [];
if (n < 1) return o;
while (n > 1) {
if (n & 1) o = o.concat(v);
n >>= 1;
v = v.concat(v);
}
return o.concat(v);
};
// curry :: ((a, b) -> c) -> a -> b -> c
const curry = f => a => b => f(a, b);
// map :: (a -> b) -> [a] -> [b]
const map = curry((f, xs) => xs.map(f));
// Apply a list of functions to a list of arguments
// <*> :: [(a -> b)] -> [a] -> [b]
const ap = (fs, xs) => //
[].concat.apply([], fs.map(f => //
[].concat.apply([], xs.map(x => [f(x)]))));
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
// intercalate :: String -> [a] -> String
const intercalate = (s, xs) => xs.join(s);
// concat :: [[a]] -> [a] || [String] -> String
const concat = xs => {
if (xs.length > 0) {
const unit = typeof xs[0] === 'string' ? '' : [];
return unit.concat.apply(unit, xs);
} else return [];
};
// TEST ------------------------------------------------------------------
return unlines(sierpTriangle(4));
})();