RosettaCodeData/Task/Population-count/JavaScript/population-count.js

131 lines
3.1 KiB
JavaScript

(() => {
'use strict';
// populationCount :: Int -> Int
const populationCount = n =>
// The number of non-zero bits in the binary
// representation of the integer n.
sum(unfoldr(
x => 0 < x ? (
Just(Tuple(x % 2)(Math.floor(x / 2)))
) : Nothing()
)(n));
// ----------------------- TEST ------------------------
// main :: IO ()
const main = () => {
const [evens, odds] = Array.from(
partition(compose(even, populationCount))(
enumFromTo(0)(59)
)
);
return [
'Population counts of the first 30 powers of three:',
` [${enumFromTo(0)(29).map(
compose(populationCount, raise(3))
).join(',')}]`,
"\nFirst thirty 'evil' numbers:",
` [${[evens.join(',')]}]`,
"\nFirst thirty 'odious' numbers:",
` [${odds.join(',')}]`
].join('\n');
};
// ----------------- GENERIC FUNCTIONS -----------------
// Just :: a -> Maybe a
const Just = x => ({
type: 'Maybe',
Nothing: false,
Just: x
});
// Nothing :: Maybe a
const Nothing = () => ({
type: 'Maybe',
Nothing: true,
});
// Tuple (,) :: a -> b -> (a, b)
const Tuple = a =>
b => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
// enumFromTo :: Int -> Int -> [Int]
const enumFromTo = m =>
n => !isNaN(m) ? (
Array.from({
length: 1 + n - m
}, (_, i) => m + i)
) : enumFromTo_(m)(n);
// even :: Int -> Bool
const even = n =>
// True if n is an even number.
0 === n % 2;
// partition :: (a -> Bool) -> [a] -> ([a], [a])
const partition = p =>
// A tuple of two lists - those elements in
// xs which match p, and those which don't.
xs => ([...xs]).reduce(
(a, x) =>
p(x) ? (
Tuple(a[0].concat(x))(a[1])
) : Tuple(a[0])(a[1].concat(x)),
Tuple([])([])
);
// raise :: Num -> Int -> Num
const raise = x =>
// X to the power of n.
n => Math.pow(x, n);
// sum :: [Num] -> Num
const sum = xs =>
// The numeric sum of all values in xs.
xs.reduce((a, x) => a + x, 0);
// unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
const unfoldr = f =>
v => {
const xs = [];
let xr = [v, v];
while (true) {
const mb = f(xr[1]);
if (mb.Nothing) {
return xs
} else {
xr = mb.Just;
xs.push(xr[0])
}
}
};
// ---
return main();
})();