September Morn Update

This commit is contained in:
Ingy döt Net 2019-09-12 10:33:56 -07:00
parent 4e2d22a71d
commit aac6731f2c
6856 changed files with 141342 additions and 21127 deletions

View file

@ -1,105 +1,145 @@
(() => {
'use strict';
// REP-CYCLES -------------------------------------------------------------
const main = () => {
// repCycles :: String -> [String]
const repCycles = xs => {
const n = xs.length;
return filter(
cs => xs === takeCycle(n, cs),
map(concat, tail(inits(take(quot(n, 2), xs))))
);
// REP-CYCLES -------------------------------------
// repCycles :: String -> [String]
const repCycles = s => {
const n = s.length;
return filter(
x => s === take(n, cycle(x)).join(''),
tail(inits(take(quot(n, 2), s)))
);
};
// TEST -------------------------------------------
console.log(fTable(
'Longest cycles:\n',
str,
xs => 0 < xs.length ? concat(last(xs)) : '(none)',
repCycles,
[
'1001110011',
'1110111011',
'0010010010',
'1010101010',
'1111111111',
'0100101101',
'0100100',
'101',
'11',
'00',
'1'
]
));
};
// cycleReport :: String -> [String]
const cycleReport = xs => {
const reps = repCycles(xs);
return [xs, isNull(reps) ? '(n/a)' : last(reps)];
};
// GENERIC FUNCTIONS ----------------------------------
// GENERIC ----------------------------------------------------------------
// compose :: (b -> c) -> (a -> b) -> (a -> c)
const compose = (f, g) => x => f(g(x));
// concat :: [[a]] -> [a] | [String] -> String
const concat = xs => {
if (xs.length > 0) {
const unit = typeof xs[0] === 'string' ? '' : [];
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (() => {
const unit = 'string' !== typeof xs[0] ? (
[]
) : '';
return unit.concat.apply(unit, xs);
} else return [];
};
})() : [];
// cons :: a -> [a] -> [a]
const cons = (x, xs) => [x].concat(xs);
// curry :: ((a, b) -> c) -> a -> b -> c
const curry = f => a => b => f(a, b);
// cycle :: [a] -> Generator [a]
function* cycle(xs) {
const lng = xs.length;
let i = 0;
while (true) {
yield(xs[i])
i = (1 + i) % lng;
}
}
// filter :: (a -> Bool) -> [a] -> [a]
const filter = (f, xs) => xs.filter(f);
// fTable :: String -> (a -> String) ->
// (b -> String) -> (a -> b) -> [a] -> String
const fTable = (s, xShow, fxShow, f, xs) => {
// Heading -> x display function ->
// fx display function ->
// f -> values -> tabular string
const
ys = xs.map(xShow),
w = Math.max(...ys.map(length));
return s + '\n' + zipWith(
(a, b) => a.padStart(w, ' ') + ' -> ' + b,
ys,
xs.map(x => fxShow(f(x)))
).join('\n');
};
// inits([1, 2, 3]) -> [[], [1], [1, 2], [1, 2, 3]
// inits('abc') -> ["", "a", "ab", "abc"]
// inits :: [a] -> [[a]]
// inits :: String -> [String]
const inits = xs => [
[]
]
.concat((typeof xs === 'string' ? xs.split('') : xs)
.map((_, i, lst) => lst.slice(0, i + 1)));
// intercalate :: String -> [a] -> String
const intercalate = (s, xs) => xs.join(s);
.concat(('string' === typeof xs ? xs.split('') : xs)
.map((_, i, lst) => lst.slice(0, 1 + i)));
// last :: [a] -> a
const last = xs => xs.length ? xs.slice(-1)[0] : undefined;
const last = xs =>
0 < xs.length ? xs.slice(-1)[0] : undefined;
// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);
// Returns Infinity over objects without finite length.
// This enables zip and zipWith to choose the shorter
// argument when one is non-finite, like cycle, repeat etc
// isNull :: [a] -> Bool
const isNull = xs => (xs instanceof Array) ? xs.length < 1 : undefined;
// length :: [a] -> Int
const length = xs =>
(Array.isArray(xs) || 'string' === typeof xs) ? (
xs.length
) : Infinity;
// Integral a => a -> a -> a
// quot :: Int -> Int -> Int
const quot = (n, m) => Math.floor(n / m);
// 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);
};
// str :: a -> String
const str = x => x.toString();
// tail :: [a] -> [a]
const tail = xs => xs.length ? xs.slice(1) : undefined;
const tail = xs => 0 < xs.length ? xs.slice(1) : [];
// take :: Int -> [a] -> [a]
const take = (n, xs) => xs.slice(0, n);
// First n members of an infinite cycle of xs
// takeCycle :: Int -> [a] -> [a]
const takeCycle = (n, xs) => {
const lng = xs.length;
return concat((lng >= n ? xs : replicate(Math.ceil(n / lng), xs)))
.slice(0, n);
};
// take :: Int -> String -> String
const take = (n, xs) =>
'GeneratorFunction' !== xs.constructor.constructor.name ? (
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.
// TEST -------------------------------------------------------------------
const samples = ["1001110011", "1110111011", "0010010010", "1010101010",
"1111111111", "0100101101", "0100100", "101", "11", "00", "1"
];
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
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));
};
return unlines(cons('Longest cycle:\n',
map(compose(curry(intercalate)(' -> '), cycleReport), samples)));
// MAIN ---
return main();
})();