Cheryl's birthday: Difference between revisions
Content added Content deleted
m (→{{header|zkl}}: ack) |
(=={{header|JavaScript}}== Added a first JS draft, aiming for some degree of legibility) |
||
Line 167: | Line 167: | ||
Cheryl's birthday is July 16 |
Cheryl's birthday is July 16 |
||
</pre> |
</pre> |
||
=={{header|JavaScript}}== |
|||
<lang javascript>(() => { |
|||
'use strict'; |
|||
// main :: IO () |
|||
const main = () => |
|||
showLog( |
|||
map(x => Array.from(x), ( |
|||
// The month with only one remaining day, |
|||
monthsWithSingleDays(true)( |
|||
// among the days with unique months, |
|||
daysWithUniqueMonths(true)( |
|||
// excluding months with unique days, |
|||
monthsWithUniqueDays(false)( |
|||
// from the given month-day pairs: |
|||
map(x => tupleFromList(words(strip(x))), |
|||
splitOn(/,\s+/, |
|||
`May 15, May 16, May 19, |
|||
June 17, June 18, July 14, July 16, |
|||
Aug 14, Aug 15, Aug 17` |
|||
) |
|||
) |
|||
) |
|||
) |
|||
) |
|||
)) |
|||
); |
|||
// monthsWithUniqueDays :: Bool -> [(Month, Day)] -> [(Month, Day)] |
|||
const monthsWithUniqueDays = blnInclude => xs => { |
|||
const |
|||
dctDays = dictFromPairs(snd)(fst)(xs), |
|||
dctMonths = dictFromPairs(fst)(snd)(xs), |
|||
days = filter( |
|||
k => 1 === length(dctDays[k]), |
|||
Object.keys(dctDays) |
|||
), |
|||
months = filter( |
|||
k => (blnInclude ? id : not)( |
|||
0 < length(intersect(dctMonths[k], days)) |
|||
), |
|||
Object.keys(dctMonths) |
|||
); |
|||
return filter(tpl => elem(fst(tpl), months), xs); |
|||
}; |
|||
// daysWithUniqueMonths :: Bool -> [(Month, Day)] -> [(Month, Day)] |
|||
const daysWithUniqueMonths = blnInclude => xs => { |
|||
const |
|||
dctDays = dictFromPairs(snd)(fst)(xs), |
|||
dctMonths = dictFromPairs(fst)(snd)(xs), |
|||
days = filter( |
|||
k => (blnInclude ? id : not)( |
|||
1 === length(dctDays[k]) |
|||
), |
|||
Object.keys(dctDays) |
|||
); |
|||
return filter(tpl => elem(snd(tpl), days), xs); |
|||
}; |
|||
// monthsWithSingleDays :: Bool -> [(Month, Day)] -> [(Month, Day)] |
|||
const monthsWithSingleDays = blnInclude => xs => { |
|||
const |
|||
dctMonths = dictFromPairs(fst)(snd)(xs), |
|||
months = filter( |
|||
k => (blnInclude ? id : not)( |
|||
1 == length(dctMonths[k]) |
|||
), |
|||
Object.keys(dctMonths) |
|||
); |
|||
return filter(tpl => elem(fst(tpl), months), xs); |
|||
}; |
|||
// dictFromPairs :: ((a, a) -> a) -> ((a, a) -> a) -> [(a, a)] -> Dict |
|||
const dictFromPairs = f => g => xs => |
|||
foldl((a, tpl) => Object.assign( |
|||
a, { |
|||
[f(tpl)]: (a[f(tpl)] || []).concat(g(tpl).toString()) |
|||
} |
|||
), {}, xs); |
|||
// GENERIC ABSTRACTIONS ------------------------------- |
|||
// Tuple (,) :: a -> b -> (a, b) |
|||
const Tuple = (a, b) => ({ |
|||
type: 'Tuple', |
|||
'0': a, |
|||
'1': b, |
|||
length: 2 |
|||
}); |
|||
// elem :: Eq a => a -> [a] -> Bool |
|||
const elem = (x, xs) => xs.includes(x); |
|||
// filter :: (a -> Bool) -> [a] -> [a] |
|||
const filter = (f, xs) => xs.filter(f); |
|||
// foldl :: (a -> b -> a) -> a -> [b] -> a |
|||
const foldl = (f, a, xs) => xs.reduce(f, a); |
|||
// fst :: (a, b) -> a |
|||
const fst = tpl => tpl[0]; |
|||
// id :: a -> a |
|||
const id = x => x; |
|||
// intersect :: (Eq a) => [a] -> [a] -> [a] |
|||
const intersect = (xs, ys) => |
|||
xs.filter(x => -1 !== ys.indexOf(x)); |
|||
// 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 |
|||
// length :: [a] -> Int |
|||
const length = xs => |
|||
(Array.isArray(xs) || 'string' === typeof xs) ? ( |
|||
xs.length |
|||
) : Infinity; |
|||
// map :: (a -> b) -> [a] -> [b] |
|||
const map = (f, xs) => xs.map(f); |
|||
// not :: Bool -> Bool |
|||
const not = b => !b; |
|||
// showLog :: a -> IO () |
|||
const showLog = (...args) => |
|||
console.log( |
|||
args |
|||
.map(JSON.stringify) |
|||
.join(' -> ') |
|||
); |
|||
// snd :: (a, b) -> b |
|||
const snd = tpl => tpl[1]; |
|||
// splitOn :: String -> String -> [String] |
|||
const splitOn = (pat, src) => |
|||
src.split(pat); |
|||
// strip :: String -> String |
|||
const strip = s => s.trim(); |
|||
// tupleFromList :: [a] -> (a, a ...) |
|||
const tupleFromList = xs => |
|||
TupleN.apply(null, xs); |
|||
// TupleN :: a -> b ... -> (a, b ... ) |
|||
function TupleN() { |
|||
const |
|||
args = Array.from(arguments), |
|||
lng = args.length; |
|||
return lng > 1 ? Object.assign( |
|||
args.reduce((a, x, i) => Object.assign(a, { |
|||
[i]: x |
|||
}), { |
|||
type: 'Tuple' + (2 < lng ? lng.toString() : ''), |
|||
length: lng |
|||
}) |
|||
) : args[0]; |
|||
}; |
|||
// words :: String -> [String] |
|||
const words = s => s.split(/\s+/); |
|||
// MAIN --- |
|||
return main(); |
|||
})();</lang> |
|||
{{Out}} |
|||
<pre>[["July","16"]]</pre> |
|||
=={{header|Perl 6}}== |
=={{header|Perl 6}}== |