RosettaCodeData/Task/Non-decimal-radices-Convert/JavaScript/non-decimal-radices-convert...

94 lines
2.4 KiB
JavaScript

(() => {
'use strict';
// toBase :: Int -> Int -> String
const toBase = (intBase, n) =>
intBase < 36 && intBase > 0 ?
inBaseDigits('0123456789abcdef'.substr(0, intBase), n) : [];
// inBaseDigits :: String -> Int -> [String]
const inBaseDigits = (digits, n) => {
const intBase = digits.length;
return unfoldr(maybeResidue => {
const [divided, remainder] = quotRem(maybeResidue.new, intBase);
return {
valid: divided > 0,
value: digits[remainder],
new: divided
};
}, n)
.reverse()
.join('');
};
// GENERIC FUNCTIONS
// unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
const unfoldr = (mf, v) => {
var xs = [];
return (until(
m => !m.valid,
m => {
const m2 = mf(m);
return (
xs = xs.concat(m2.value),
m2
);
}, {
valid: true,
value: v,
new: v,
}
), xs);
};
// curry :: ((a, b) -> c) -> a -> b -> c
const curry = f => a => b => f(a, b);
// until :: (a -> Bool) -> (a -> a) -> a -> a
const until = (p, f, x) => {
let v = x;
while (!p(v)) v = f(v);
return v;
}
// quotRem :: Integral a => a -> a -> (a, a)
const quotRem = (m, n) => [Math.floor(m / n), m % n];
// show :: a -> String
const show = x => JSON.stringify(x, null, 2);
// OTHER FUNCTIONS DERIVABLE FROM inBaseDigits
// inLowerHex :: Int -> String
const inLowerHex = curry(inBaseDigits)('0123456789abcdef');
/// inUpperHex :: Int -> String
const inUpperHex = curry(inBaseDigits)('0123456789ABCDEF');
// inOctal :: Int -> String
const inOctal = curry(inBaseDigits)('01234567');
// inDevanagariDecimal :: Int -> String
const inDevanagariDecimal = curry(inBaseDigits)('०१२३४५६७८९');
// TESTS
// testNumber :: [Int]
const testNumbers = [255, 240];
return testNumbers.map(n => show({
binary: toBase(2, n),
base5: toBase(5, n),
hex: toBase(16, n),
upperHex: inUpperHex(n),
octal: inOctal(n),
devanagariDecimal: inDevanagariDecimal(n)
}));
})();