September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
|
|
@ -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();
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue