Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
|
|
@ -0,0 +1,209 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
// duplicatedCharIndices :: String -> Maybe (Char, [Int])
|
||||
const duplicatedCharIndices = s => {
|
||||
const
|
||||
duplicates = filter(g => 1 < g.length)(
|
||||
groupBy(on(eq)(snd))(
|
||||
sortOn(snd)(
|
||||
zip(enumFrom(0))(chars(s))
|
||||
)
|
||||
)
|
||||
);
|
||||
return 0 < duplicates.length ? Just(
|
||||
fanArrow(compose(snd, fst))(map(fst))(
|
||||
sortOn(compose(fst, fst))(
|
||||
duplicates
|
||||
)[0]
|
||||
)
|
||||
) : Nothing();
|
||||
};
|
||||
|
||||
// ------------------------TEST------------------------
|
||||
const main = () =>
|
||||
console.log(
|
||||
fTable('First duplicated character, if any:')(
|
||||
s => `'${s}' (${s.length})`
|
||||
)(maybe('None')(tpl => {
|
||||
const [c, ixs] = Array.from(tpl);
|
||||
return `'${c}' (0x${showHex(ord(c))}) at ${ixs.join(', ')}`
|
||||
}))(duplicatedCharIndices)([
|
||||
"", ".", "abcABC", "XYZ ZYX",
|
||||
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
|
||||
])
|
||||
);
|
||||
|
||||
|
||||
// -----------------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
|
||||
});
|
||||
|
||||
// chars :: String -> [Char]
|
||||
const chars = s => s.split('');
|
||||
|
||||
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
|
||||
const compose = (...fs) =>
|
||||
x => fs.reduceRight((a, f) => f(a), x);
|
||||
|
||||
// enumFrom :: Enum a => a -> [a]
|
||||
function* enumFrom(x) {
|
||||
let v = x;
|
||||
while (true) {
|
||||
yield v;
|
||||
v = 1 + v;
|
||||
}
|
||||
}
|
||||
|
||||
// eq (==) :: Eq a => a -> a -> Bool
|
||||
const eq = a => b => a === b;
|
||||
|
||||
// fanArrow (&&&) :: (a -> b) -> (a -> c) -> (a -> (b, c))
|
||||
const fanArrow = f =>
|
||||
// Compose a function from a simple value to a tuple of
|
||||
// the separate outputs of two different functions.
|
||||
g => x => Tuple(f(x))(g(x));
|
||||
|
||||
// filter :: (a -> Bool) -> [a] -> [a]
|
||||
const filter = f => xs => xs.filter(f);
|
||||
|
||||
// fst :: (a, b) -> a
|
||||
const fst = tpl => tpl[0];
|
||||
|
||||
// fTable :: String -> (a -> String) -> (b -> String)
|
||||
// -> (a -> b) -> [a] -> String
|
||||
const fTable = s => xShow => fxShow => f => xs => {
|
||||
// Heading -> x display function ->
|
||||
// fx display function ->
|
||||
// f -> values -> tabular string
|
||||
const
|
||||
ys = xs.map(xShow),
|
||||
w = Math.max(...ys.map(length));
|
||||
return s + '\n' + zipWith(
|
||||
a => b => a.padStart(w, ' ') + ' -> ' + b
|
||||
)(ys)(
|
||||
xs.map(x => fxShow(f(x)))
|
||||
).join('\n');
|
||||
};
|
||||
|
||||
// groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
|
||||
const groupBy = fEq =>
|
||||
// Typical usage: groupBy(on(eq)(f), xs)
|
||||
xs => 0 < xs.length ? (() => {
|
||||
const
|
||||
tpl = xs.slice(1).reduce(
|
||||
(gw, x) => {
|
||||
const
|
||||
gps = gw[0],
|
||||
wkg = gw[1];
|
||||
return fEq(wkg[0])(x) ? (
|
||||
Tuple(gps)(wkg.concat([x]))
|
||||
) : Tuple(gps.concat([wkg]))([x]);
|
||||
},
|
||||
Tuple([])([xs[0]])
|
||||
);
|
||||
return tpl[0].concat([tpl[1]])
|
||||
})() : [];
|
||||
|
||||
// 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;
|
||||
|
||||
// map :: (a -> b) -> [a] -> [b]
|
||||
const map = f => xs =>
|
||||
(Array.isArray(xs) ? (
|
||||
xs
|
||||
) : xs.split('')).map(f);
|
||||
|
||||
// maybe :: b -> (a -> b) -> Maybe a -> b
|
||||
const maybe = v =>
|
||||
// Default value (v) if m is Nothing, or f(m.Just)
|
||||
f => m => m.Nothing ? v : f(m.Just);
|
||||
|
||||
// on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
|
||||
const on = f =>
|
||||
g => a => b => f(g(a))(g(b));
|
||||
|
||||
// ord :: Char -> Int
|
||||
const ord = c => c.codePointAt(0);
|
||||
|
||||
// showHex :: Int -> String
|
||||
const showHex = n =>
|
||||
n.toString(16);
|
||||
|
||||
// snd :: (a, b) -> b
|
||||
const snd = tpl => tpl[1];
|
||||
|
||||
// sortOn :: Ord b => (a -> b) -> [a] -> [a]
|
||||
const sortOn = f =>
|
||||
// Equivalent to sortBy(comparing(f)), but with f(x)
|
||||
// evaluated only once for each x in xs.
|
||||
// ('Schwartzian' decorate-sort-undecorate).
|
||||
xs => xs.map(
|
||||
x => [f(x), x]
|
||||
).sort(
|
||||
(a, b) => a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0)
|
||||
).map(x => x[1]);
|
||||
|
||||
// take :: Int -> [a] -> [a]
|
||||
// take :: Int -> String -> String
|
||||
const take = n => 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];
|
||||
}));
|
||||
|
||||
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
|
||||
const uncurry = f =>
|
||||
(x, y) => f(x)(y)
|
||||
|
||||
// zip :: [a] -> [b] -> [(a, b)]
|
||||
const zip = xs => ys => {
|
||||
const
|
||||
lng = Math.min(length(xs), length(ys)),
|
||||
vs = take(lng)(ys);
|
||||
return take(lng)(xs)
|
||||
.map((x, i) => Tuple(x)(vs[i]));
|
||||
};
|
||||
|
||||
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
||||
const zipWith = f =>
|
||||
xs => ys => {
|
||||
const
|
||||
lng = Math.min(length(xs), length(ys)),
|
||||
vs = take(lng)(ys);
|
||||
return take(lng)(xs)
|
||||
.map((x, i) => f(x)(vs[i]));
|
||||
};
|
||||
|
||||
// MAIN ---
|
||||
return main();
|
||||
})();
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
// duplicatedCharIndices :: String -> Maybe (Char, [Int])
|
||||
const duplicatedCharIndices = s =>
|
||||
minimumByMay(
|
||||
comparing(compose(fst, snd))
|
||||
)(filter(x => 1 < x[1].length)(
|
||||
Object.entries(
|
||||
s.split('').reduce(
|
||||
(a, c, i) => Object.assign(a, {
|
||||
[c]: (a[c] || []).concat(i)
|
||||
}), {}
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// ------------------------TEST------------------------
|
||||
const main = () =>
|
||||
console.log(
|
||||
fTable('First duplicated character, if any:')(
|
||||
s => `'${s}' (${s.length })`
|
||||
)(maybe('None')(tpl => {
|
||||
const [c, ixs] = Array.from(tpl);
|
||||
return `'${c}' (0x${showHex(ord(c))}) at ${ixs.join(', ')}`
|
||||
}))(duplicatedCharIndices)([
|
||||
"", ".", "abcABC", "XYZ ZYX",
|
||||
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
|
||||
])
|
||||
);
|
||||
|
||||
|
||||
// -----------------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
|
||||
});
|
||||
|
||||
// chars :: String -> [Char]
|
||||
const chars = s => s.split('');
|
||||
|
||||
// comparing :: (a -> b) -> (a -> a -> Ordering)
|
||||
const comparing = f =>
|
||||
x => y => {
|
||||
const
|
||||
a = f(x),
|
||||
b = f(y);
|
||||
return a < b ? -1 : (a > b ? 1 : 0);
|
||||
};
|
||||
|
||||
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
|
||||
const compose = (...fs) =>
|
||||
x => fs.reduceRight((a, f) => f(a), x);
|
||||
|
||||
// enumFrom :: Enum a => a -> [a]
|
||||
function* enumFrom(x) {
|
||||
let v = x;
|
||||
while (true) {
|
||||
yield v;
|
||||
v = 1 + v;
|
||||
}
|
||||
}
|
||||
|
||||
// filter :: (a -> Bool) -> [a] -> [a]
|
||||
const filter = f => xs => xs.filter(f);
|
||||
|
||||
// fst :: (a, b) -> a
|
||||
const fst = tpl => tpl[0];
|
||||
|
||||
// fTable :: String -> (a -> String) -> (b -> String)
|
||||
// -> (a -> b) -> [a] -> String
|
||||
const fTable = s => xShow => fxShow => f => xs => {
|
||||
// Heading -> x display function ->
|
||||
// fx display function ->
|
||||
// f -> values -> tabular string
|
||||
const
|
||||
ys = xs.map(xShow),
|
||||
w = Math.max(...ys.map(length));
|
||||
return s + '\n' + zipWith(
|
||||
a => b => a.padStart(w, ' ') + ' -> ' + b
|
||||
)(ys)(
|
||||
xs.map(x => fxShow(f(x)))
|
||||
).join('\n');
|
||||
};
|
||||
|
||||
// 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;
|
||||
|
||||
// maybe :: b -> (a -> b) -> Maybe a -> b
|
||||
const maybe = v =>
|
||||
// Default value (v) if m is Nothing, or f(m.Just)
|
||||
f => m => m.Nothing ? v : f(m.Just);
|
||||
|
||||
// minimumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a
|
||||
const minimumByMay = f =>
|
||||
xs => xs.reduce((a, x) =>
|
||||
a.Nothing ? Just(x) : (
|
||||
f(x)(a.Just) < 0 ? Just(x) : a
|
||||
), Nothing());
|
||||
|
||||
// ord :: Char -> Int
|
||||
const ord = c => c.codePointAt(0);
|
||||
|
||||
// showHex :: Int -> String
|
||||
const showHex = n =>
|
||||
n.toString(16);
|
||||
|
||||
// snd :: (a, b) -> b
|
||||
const snd = tpl =>
|
||||
tpl[1];
|
||||
|
||||
// take :: Int -> [a] -> [a]
|
||||
// take :: Int -> String -> String
|
||||
const take = n =>
|
||||
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];
|
||||
}));
|
||||
|
||||
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
||||
const zipWith = f =>
|
||||
xs => ys => {
|
||||
const
|
||||
lng = Math.min(length(xs), length(ys)),
|
||||
vs = take(lng)(ys);
|
||||
return take(lng)(xs)
|
||||
.map((x, i) => f(x)(vs[i]));
|
||||
};
|
||||
|
||||
// MAIN ---
|
||||
return main();
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue