September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
|
|
@ -1,68 +1,120 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
// PASCAL'S TRIANGLE ------------------------------------------------------
|
||||
|
||||
// pascal :: Int -> [[Int]]
|
||||
const pascal = n =>
|
||||
foldl(a => {
|
||||
const xs = a.slice(-1)[0]; // Previous row
|
||||
return append(a, [
|
||||
zipWith(
|
||||
(a, b) => a + b,
|
||||
append([0], xs),
|
||||
append(xs, [0])
|
||||
)
|
||||
]);
|
||||
}, [
|
||||
[1] // Initial seed row
|
||||
], enumFromTo(1, n - 1));
|
||||
const main = () =>
|
||||
showPascal(take(7, pascal()));
|
||||
|
||||
|
||||
// GENERIC FUNCTIONS ------------------------------------------------------
|
||||
// pascal :: Generator [[Int]]
|
||||
const pascal = () =>
|
||||
iterate(
|
||||
xs => zipWith(
|
||||
plus,
|
||||
append([0], xs), append(xs, [0])
|
||||
),
|
||||
[1]
|
||||
);
|
||||
|
||||
// (++) :: [a] -> [a] -> [a]
|
||||
// showPascal :: [[Int]] -> String
|
||||
const showPascal = xs => {
|
||||
const
|
||||
w = length(intercalate(' ', last(xs))),
|
||||
align = xs => center(w, ' ', intercalate(' ', xs));
|
||||
return unlines(map(align, xs));
|
||||
};
|
||||
|
||||
|
||||
// GENERIC FUNCTIONS ----------------------------------
|
||||
|
||||
// Tuple (,) :: a -> b -> (a, b)
|
||||
const Tuple = (a, b) => ({
|
||||
type: 'Tuple',
|
||||
'0': a,
|
||||
'1': b,
|
||||
length: 2
|
||||
});
|
||||
|
||||
// append (++) :: [a] -> [a] -> [a]
|
||||
// append (++) :: String -> String -> String
|
||||
const append = (xs, ys) => xs.concat(ys);
|
||||
|
||||
// enumFromTo :: Int -> Int -> [Int]
|
||||
const enumFromTo = (m, n) =>
|
||||
Array.from({
|
||||
length: Math.floor(n - m) + 1
|
||||
}, (_, i) => m + i);
|
||||
// Size of space -> filler Char -> String -> Centered String
|
||||
|
||||
// flip :: (a -> b -> c) -> b -> a -> c
|
||||
const flip = f => (a, b) => f(b, a);
|
||||
// center :: Int -> Char -> String -> String
|
||||
const center = (n, c, s) => {
|
||||
const
|
||||
qr = quotRem(n - s.length, 2),
|
||||
q = qr[0];
|
||||
return replicateString(q, c) +
|
||||
s + replicateString(q + qr[1], c);
|
||||
};
|
||||
|
||||
// foldl :: (b -> a -> b) -> b -> [a] -> b
|
||||
const foldl = (f, a, xs) => xs.reduce(f, a);
|
||||
// intercalate :: String -> [String] -> String
|
||||
const intercalate = (s, xs) =>
|
||||
xs.join(s);
|
||||
|
||||
// foldr (a -> b -> b) -> b -> [a] -> b
|
||||
const foldr = (f, a, xs) => xs.reduceRight(flip(f), a);
|
||||
// iterate :: (a -> a) -> a -> Generator [a]
|
||||
function* iterate(f, x) {
|
||||
let v = x;
|
||||
while (true) {
|
||||
yield(v);
|
||||
v = f(v);
|
||||
}
|
||||
}
|
||||
|
||||
// last :: [a] -> a
|
||||
const last = xs =>
|
||||
0 < xs.length ? xs.slice(-1)[0] : undefined;
|
||||
|
||||
// Returns Infinity over objects without finite length
|
||||
// this enables zip and zipWith to choose the shorter
|
||||
// argument when one non-finite like cycle, repeat etc
|
||||
|
||||
// length :: [a] -> Int
|
||||
const length = xs => xs.length || Infinity;
|
||||
|
||||
// map :: (a -> b) -> [a] -> [b]
|
||||
const map = (f, xs) => xs.map(f);
|
||||
|
||||
// min :: Ord a => a -> a -> a
|
||||
const min = (a, b) => b < a ? b : a;
|
||||
// plus :: Num -> Num -> Num
|
||||
const plus = (a, b) => a + b;
|
||||
|
||||
// quotRem :: Int -> Int -> (Int, Int)
|
||||
const quotRem = (m, n) =>
|
||||
Tuple(Math.floor(m / n), m % n);
|
||||
|
||||
// replicateString :: Int -> String -> String
|
||||
const replicateString = (n, s) => s.repeat(n);
|
||||
|
||||
// take :: Int -> [a] -> [a]
|
||||
// take :: Int -> String -> String
|
||||
const take = (n, xs) =>
|
||||
xs.constructor.constructor.name !== 'GeneratorFunction' ? (
|
||||
xs.slice(0, n)
|
||||
) : [].concat.apply([], Array.from({
|
||||
length: n
|
||||
}, () => {
|
||||
const x = xs.next();
|
||||
return x.done ? [] : [x.value];
|
||||
}));
|
||||
|
||||
// unlines :: [String] -> String
|
||||
const unlines = xs => xs.join('\n');
|
||||
|
||||
// Use of `take` and `length` here allows zipping with non-finite lists
|
||||
// i.e. generators like cycle, repeat, iterate.
|
||||
|
||||
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
||||
const zipWith = (f, xs, ys) =>
|
||||
Array.from({
|
||||
length: min(xs.length, ys.length)
|
||||
}, (_, i) => f(xs[i], ys[i]));
|
||||
const zipWith = (f, xs, ys) => {
|
||||
const
|
||||
lng = Math.min(length(xs), length(ys)),
|
||||
as = take(lng, xs),
|
||||
bs = take(lng, ys);
|
||||
return Array.from({
|
||||
length: lng
|
||||
}, (_, i) => f(as[i], bs[i], i));
|
||||
};
|
||||
|
||||
// TEST -------------------------------------------------------------------
|
||||
return foldr((x, a) => {
|
||||
const strIndent = a.indent;
|
||||
return {
|
||||
rows: strIndent + map(n => (' ' + n)
|
||||
.slice(-4), x)
|
||||
.join('') + '\n' + a.rows,
|
||||
indent: strIndent + ' '
|
||||
};
|
||||
}, {
|
||||
rows: '',
|
||||
indent: ''
|
||||
}, pascal(7))
|
||||
.rows;
|
||||
// MAIN ---
|
||||
return main();
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue