Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
429
Task/CUSIP/JavaScript/cusip.js
Normal file
429
Task/CUSIP/JavaScript/cusip.js
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
// cusipValid = Dict Char Int -> String -> Bool
|
||||
const cusipValid = charMap => s => {
|
||||
const
|
||||
ns = fromMaybe([])(
|
||||
traverse(flip(lookupDict)(charMap))(
|
||||
chars(s)
|
||||
)
|
||||
);
|
||||
return 9 === ns.length && (
|
||||
last(ns) === rem(
|
||||
10 - rem(
|
||||
sum(apList(
|
||||
apList([quot, rem])(
|
||||
zipWith(identity)(
|
||||
cycle([identity, x => 2 * x])
|
||||
)(take(8)(ns))
|
||||
)
|
||||
)([10]))
|
||||
)(10)
|
||||
)(10)
|
||||
);
|
||||
};
|
||||
|
||||
//----------------------- TEST ------------------------
|
||||
// main :: IO ()
|
||||
const main = () => {
|
||||
|
||||
// cusipMap :: Dict Char Int
|
||||
const cusipMap = dictFromList(
|
||||
zip(chars(
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#"
|
||||
))(enumFrom(0)));
|
||||
|
||||
console.log(unlines(map(
|
||||
apFn(
|
||||
s => validity => s + ' -> ' + str(validity)
|
||||
)(cusipValid(cusipMap))
|
||||
)([
|
||||
'037833100',
|
||||
'17275R102',
|
||||
'38259P508',
|
||||
'594918104',
|
||||
'68389X106',
|
||||
'68389X105'
|
||||
])));
|
||||
};
|
||||
|
||||
|
||||
//----------------- 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
|
||||
});
|
||||
|
||||
|
||||
// apFn :: (a -> b -> c) -> (a -> b) -> a -> c
|
||||
const apFn = f =>
|
||||
// Applicative instance for functions.
|
||||
// f(x) applied to g(x).
|
||||
g => x => f(x)(
|
||||
g(x)
|
||||
);
|
||||
|
||||
|
||||
// apList (<*>) :: [(a -> b)] -> [a] -> [b]
|
||||
const apList = fs =>
|
||||
// The sequential application of each of a list
|
||||
// of functions to each of a list of values.
|
||||
xs => fs.flatMap(
|
||||
f => xs.map(f)
|
||||
);
|
||||
|
||||
|
||||
// append (++) :: [a] -> [a] -> [a]
|
||||
// append (++) :: String -> String -> String
|
||||
const append = xs =>
|
||||
// A list or string composed by
|
||||
// the concatenation of two others.
|
||||
ys => xs.concat(ys);
|
||||
|
||||
|
||||
// chars :: String -> [Char]
|
||||
const chars = s =>
|
||||
s.split('');
|
||||
|
||||
|
||||
// cons :: a -> [a] -> [a]
|
||||
const cons = x =>
|
||||
xs => Array.isArray(xs) ? (
|
||||
[x].concat(xs)
|
||||
) : 'GeneratorFunction' !== xs
|
||||
.constructor.constructor.name ? (
|
||||
x + xs
|
||||
) : ( // cons(x)(Generator)
|
||||
function*() {
|
||||
yield x;
|
||||
let nxt = xs.next()
|
||||
while (!nxt.done) {
|
||||
yield nxt.value;
|
||||
nxt = xs.next();
|
||||
}
|
||||
}
|
||||
)();
|
||||
|
||||
|
||||
// cycle :: [a] -> Generator [a]
|
||||
function* cycle(xs) {
|
||||
const lng = xs.length;
|
||||
let i = 0;
|
||||
while (true) {
|
||||
yield(xs[i])
|
||||
i = (1 + i) % lng;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// dictFromList :: [(k, v)] -> Dict
|
||||
const dictFromList = kvs =>
|
||||
Object.fromEntries(kvs);
|
||||
|
||||
|
||||
// enumFrom :: Enum a => a -> [a]
|
||||
function* enumFrom(x) {
|
||||
// A non-finite succession of enumerable
|
||||
// values, starting with the value x.
|
||||
let v = x;
|
||||
while (true) {
|
||||
yield v;
|
||||
v = succ(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// flip :: (a -> b -> c) -> b -> a -> c
|
||||
const flip = f =>
|
||||
1 < f.length ? (
|
||||
(a, b) => f(b, a)
|
||||
) : (x => y => f(y)(x));
|
||||
|
||||
|
||||
// fromEnum :: Enum a => a -> Int
|
||||
const fromEnum = x =>
|
||||
typeof x !== 'string' ? (
|
||||
x.constructor === Object ? (
|
||||
x.value
|
||||
) : parseInt(Number(x))
|
||||
) : x.codePointAt(0);
|
||||
|
||||
|
||||
// fromMaybe :: a -> Maybe a -> a
|
||||
const fromMaybe = def =>
|
||||
// A default value if mb is Nothing
|
||||
// or the contents of mb.
|
||||
mb => mb.Nothing ? def : mb.Just;
|
||||
|
||||
|
||||
// fst :: (a, b) -> a
|
||||
const fst = tpl =>
|
||||
// First member of a pair.
|
||||
tpl[0];
|
||||
|
||||
|
||||
// identity :: a -> a
|
||||
const identity = x =>
|
||||
// The identity function. (`id`, in Haskell)
|
||||
x;
|
||||
|
||||
|
||||
// last :: [a] -> a
|
||||
const last = xs =>
|
||||
// The last item of a list.
|
||||
0 < xs.length ? xs.slice(-1)[0] : undefined;
|
||||
|
||||
|
||||
// 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
|
||||
(Array.isArray(xs) || 'string' === typeof xs) ? (
|
||||
xs.length
|
||||
) : Infinity;
|
||||
|
||||
|
||||
// liftA2 :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
|
||||
const liftA2 = f => a => b =>
|
||||
a.Nothing ? a : b.Nothing ? b : Just(f(a.Just)(b.Just));
|
||||
|
||||
|
||||
// lookupDict :: a -> Dict -> Maybe b
|
||||
const lookupDict = k => dct => {
|
||||
const v = dct[k];
|
||||
return undefined !== v ? (
|
||||
Just(v)
|
||||
) : Nothing();
|
||||
};
|
||||
|
||||
// map :: (a -> b) -> [a] -> [b]
|
||||
const map = f =>
|
||||
// The list obtained by applying f
|
||||
// to each element of xs.
|
||||
// (The image of xs under f).
|
||||
xs => (
|
||||
Array.isArray(xs) ? (
|
||||
xs
|
||||
) : xs.split('')
|
||||
).map(f);
|
||||
|
||||
|
||||
// pureMay :: a -> Maybe a
|
||||
const pureMay = x => Just(x);
|
||||
|
||||
// Given a type name string, returns a
|
||||
// specialised 'pure', where
|
||||
// 'pure' lifts a value into a particular functor.
|
||||
|
||||
// pureT :: String -> f a -> (a -> f a)
|
||||
const pureT = t => x =>
|
||||
'List' !== t ? (
|
||||
'Either' === t ? (
|
||||
pureLR(x)
|
||||
) : 'Maybe' === t ? (
|
||||
pureMay(x)
|
||||
) : 'Node' === t ? (
|
||||
pureTree(x)
|
||||
) : 'Tuple' === t ? (
|
||||
pureTuple(x)
|
||||
) : pureList(x)
|
||||
) : pureList(x);
|
||||
|
||||
|
||||
// pureTuple :: a -> (a, a)
|
||||
const pureTuple = x =>
|
||||
Tuple('')(x);
|
||||
|
||||
// quot :: Int -> Int -> Int
|
||||
const quot = n =>
|
||||
m => Math.floor(n / m);
|
||||
|
||||
// rem :: Int -> Int -> Int
|
||||
const rem = n => m => n % m;
|
||||
|
||||
// snd :: (a, b) -> b
|
||||
const snd = tpl => tpl[1];
|
||||
|
||||
// str :: a -> String
|
||||
const str = x =>
|
||||
x.toString();
|
||||
|
||||
// succ :: Enum a => a -> a
|
||||
const succ = x => {
|
||||
const t = typeof x;
|
||||
return 'number' !== t ? (() => {
|
||||
const [i, mx] = [x, maxBound(x)].map(fromEnum);
|
||||
return i < mx ? (
|
||||
toEnum(x)(1 + i)
|
||||
) : Error('succ :: enum out of range.')
|
||||
})() : x < Number.MAX_SAFE_INTEGER ? (
|
||||
1 + x
|
||||
) : Error('succ :: Num out of range.')
|
||||
};
|
||||
|
||||
// sum :: [Num] -> Num
|
||||
const sum = xs =>
|
||||
// The numeric sum of all values in xs.
|
||||
xs.reduce((a, x) => a + x, 0);
|
||||
|
||||
// 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];
|
||||
}));
|
||||
|
||||
// The first argument is a sample of the type
|
||||
// allowing the function to make the right mapping
|
||||
|
||||
// toEnum :: a -> Int -> a
|
||||
const toEnum = e => x =>
|
||||
({
|
||||
'number': Number,
|
||||
'string': String.fromCodePoint,
|
||||
'boolean': Boolean,
|
||||
'object': v => e.min + v
|
||||
} [typeof e])(x);
|
||||
|
||||
|
||||
// traverse :: (Applicative f) => (a -> f b) -> [a] -> f [b]
|
||||
const traverse = f =>
|
||||
// Collected results of mapping each element
|
||||
// of a structure to an action, and evaluating
|
||||
// these actions from left to right.
|
||||
xs => 0 < xs.length ? (() => {
|
||||
const
|
||||
vLast = f(xs.slice(-1)[0]),
|
||||
t = vLast.type || 'List';
|
||||
return xs.slice(0, -1).reduceRight(
|
||||
(ys, x) => liftA2(cons)(f(x))(ys),
|
||||
liftA2(cons)(vLast)(pureT(t)([]))
|
||||
);
|
||||
})() : [
|
||||
[]
|
||||
];
|
||||
|
||||
|
||||
// uncons :: [a] -> Maybe (a, [a])
|
||||
const uncons = xs => {
|
||||
// Just a tuple of the head of xs and its tail,
|
||||
// Or Nothing if xs is an empty list.
|
||||
const lng = length(xs);
|
||||
return (0 < lng) ? (
|
||||
Infinity > lng ? (
|
||||
Just(Tuple(xs[0])(xs.slice(1))) // Finite list
|
||||
) : (() => {
|
||||
const nxt = take(1)(xs);
|
||||
return 0 < nxt.length ? (
|
||||
Just(Tuple(nxt[0])(xs))
|
||||
) : Nothing();
|
||||
})() // Lazy generator
|
||||
) : Nothing();
|
||||
};
|
||||
|
||||
|
||||
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
|
||||
const uncurry = f =>
|
||||
// A function over a pair, derived
|
||||
// from a curried function.
|
||||
x => ((...args) => {
|
||||
const
|
||||
xy = 1 < args.length ? (
|
||||
args
|
||||
) : args[0];
|
||||
return f(xy[0])(xy[1]);
|
||||
})(x);
|
||||
|
||||
|
||||
// unlines :: [String] -> String
|
||||
const unlines = xs =>
|
||||
// A single string formed by the intercalation
|
||||
// of a list of strings with the newline character.
|
||||
xs.join('\n');
|
||||
|
||||
|
||||
// zip :: [a] -> [b] -> [(a, b)]
|
||||
const zip = xs =>
|
||||
// Use of `take` and `length` here allows for zipping with non-finite
|
||||
// lists - i.e. generators like cycle, repeat, iterate.
|
||||
ys => {
|
||||
const
|
||||
lng = Math.min(length(xs), length(ys)),
|
||||
vs = take(lng)(ys);
|
||||
return take(lng)(xs).map(
|
||||
(x, i) => Tuple(x)(vs[i])
|
||||
);
|
||||
};
|
||||
|
||||
// Use of `take` and `length` here allows zipping with non-finite lists
|
||||
// i.e. generators like cycle, repeat, iterate.
|
||||
|
||||
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
||||
const zipWith = f => xs => ys => {
|
||||
const lng = Math.min(length(xs), length(ys));
|
||||
return Infinity > lng ? (() => {
|
||||
const
|
||||
as = take(lng)(xs),
|
||||
bs = take(lng)(ys);
|
||||
return Array.from({
|
||||
length: lng
|
||||
}, (_, i) => f(as[i])(
|
||||
bs[i]
|
||||
));
|
||||
})() : zipWithGen(f)(xs)(ys);
|
||||
};
|
||||
|
||||
|
||||
// zipWithGen :: (a -> b -> c) ->
|
||||
// Gen [a] -> Gen [b] -> Gen [c]
|
||||
const zipWithGen = f => ga => gb => {
|
||||
function* go(ma, mb) {
|
||||
let
|
||||
a = ma,
|
||||
b = mb;
|
||||
while (!a.Nothing && !b.Nothing) {
|
||||
let
|
||||
ta = a.Just,
|
||||
tb = b.Just
|
||||
yield(f(fst(ta))(fst(tb)));
|
||||
a = uncons(snd(ta));
|
||||
b = uncons(snd(tb));
|
||||
}
|
||||
}
|
||||
return go(uncons(ga), uncons(gb));
|
||||
};
|
||||
|
||||
// MAIN ---
|
||||
return main();
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue