RosettaCodeData/Task/Mian-Chowla-sequence/JavaScript/mian-chowla-sequence.js

112 lines
2.8 KiB
JavaScript

(() => {
'use strict';
// main :: IO ()
const main = () => {
const genMianChowla = mianChowlas();
console.log([
'Mian-Chowla terms 1-30:',
take(30)(
genMianChowla
),
'\nMian-Chowla terms 91-100:',
(
drop(60)(genMianChowla),
take(10)(
genMianChowla
)
)
].join('\n') + '\n');
};
// mianChowlas :: Gen [Int]
function* mianChowlas() {
let
mcs = [1],
sumSet = new Set([2]),
x = 1;
while (true) {
yield x;
[sumSet, mcs, x] = nextMC(sumSet, mcs, x);
}
}
// nextMC :: Set Int -> [Int] -> Int -> (Set Int, [Int], Int)
const nextMC = (setSums, mcs, n) => {
// Set of sums -> Series up to n -> Next term in series
const valid = x => {
for (const m of mcs) {
if (setSums.has(x + m)) return false;
}
return true;
};
const x = until(valid)(x => 1 + x)(n);
return [
sumList(mcs)(x)
.reduce(
(a, n) => (a.add(n), a),
setSums
),
mcs.concat(x),
x
];
};
// sumList :: [Int] -> Int -> [Int]
const sumList = xs =>
// Series so far -> additional term -> new sums
n => [2 * n].concat(xs.map(x => n + x));
// ---------------- GENERIC FUNCTIONS ----------------
// drop :: Int -> [a] -> [a]
// drop :: Int -> Generator [a] -> Generator [a]
// drop :: Int -> String -> String
const drop = n =>
xs => Infinity > length(xs) ? (
xs.slice(n)
) : (take(n)(xs), xs);
// length :: [a] -> Int
const length = xs =>
// 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
'GeneratorFunction' !== xs.constructor
.constructor.name ? (
xs.length
) : Infinity;
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take = n =>
// The first n elements of a list,
// string of characters, or stream.
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];
}));
// until :: (a -> Bool) -> (a -> a) -> a -> a
const until = p =>
f => x => {
let v = x;
while (!p(v)) v = f(v);
return v;
};
// MAIN ---
return main();
})();