82 lines
1.9 KiB
JavaScript
82 lines
1.9 KiB
JavaScript
(() => {
|
|
'use strict';
|
|
|
|
// vanEck :: Int -> [Int]
|
|
const vanEck = n =>
|
|
reverse(
|
|
churchNumeral(n)(
|
|
xs => 0 < xs.length ? cons(
|
|
maybe(
|
|
0, succ,
|
|
elemIndex(xs[0], xs.slice(1))
|
|
),
|
|
xs
|
|
) : [0]
|
|
)([])
|
|
);
|
|
|
|
// TEST -----------------------------------------------
|
|
const main = () => {
|
|
console.log('VanEck series:\n')
|
|
showLog('First 10 terms', vanEck(10))
|
|
showLog('Terms 991-1000', vanEck(1000).slice(990))
|
|
};
|
|
|
|
// GENERIC FUNCTIONS ----------------------------------
|
|
|
|
// Just :: a -> Maybe a
|
|
const Just = x => ({
|
|
type: 'Maybe',
|
|
Nothing: false,
|
|
Just: x
|
|
});
|
|
|
|
// Nothing :: Maybe a
|
|
const Nothing = () => ({
|
|
type: 'Maybe',
|
|
Nothing: true,
|
|
});
|
|
|
|
// churchNumeral :: Int -> (a -> a) -> a -> a
|
|
const churchNumeral = n => f => x =>
|
|
Array.from({
|
|
length: n
|
|
}, () => f)
|
|
.reduce((a, g) => g(a), x)
|
|
|
|
// cons :: a -> [a] -> [a]
|
|
const cons = (x, xs) => [x].concat(xs)
|
|
|
|
// elemIndex :: Eq a => a -> [a] -> Maybe Int
|
|
const elemIndex = (x, xs) => {
|
|
const i = xs.indexOf(x);
|
|
return -1 === i ? (
|
|
Nothing()
|
|
) : Just(i);
|
|
};
|
|
|
|
// maybe :: b -> (a -> b) -> Maybe a -> b
|
|
const maybe = (v, f, m) =>
|
|
m.Nothing ? v : f(m.Just);
|
|
|
|
// reverse :: [a] -> [a]
|
|
const reverse = xs =>
|
|
'string' !== typeof xs ? (
|
|
xs.slice(0).reverse()
|
|
) : xs.split('').reverse().join('');
|
|
|
|
// showLog :: a -> IO ()
|
|
const showLog = (...args) =>
|
|
console.log(
|
|
args
|
|
.map(JSON.stringify)
|
|
.join(' -> ')
|
|
);
|
|
|
|
// succ :: Int -> Int
|
|
const succ = x => 1 + x;
|
|
|
|
// MAIN ---
|
|
return main();
|
|
})();
|