Created
April 24, 2018 20:38
-
-
Save bas080/818f1002d60276fd4ecc5f505ee2ab8d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function next(current = []) { | |
if (current.length === 0) | |
return [1] | |
if (current.length === 1) | |
return [1, 1] | |
return [1, ...nextIter(current), 1] | |
} | |
function nextIter(items, acc = []) { | |
if (items.length === 1) | |
return acc | |
const [first, second, ...rest] = items | |
return nextIter( | |
[second, ...rest], | |
[...acc, sum(first, second)] | |
) | |
} | |
function sum(a, b) { | |
return a + b | |
} | |
function times(fn, n) { | |
if (n === 0) | |
return [fn(n)] | |
return [...times(fn, n - 1), fn(n)] | |
} | |
function pascal(rows = 10) { | |
let value = [] | |
return times(n => { | |
value = next(value) | |
return value | |
}, rows) | |
} | |
console.log(pascal(5)) | |
function isDivisibleBy(n) { | |
return value => (value % n) === 0 && value !== 0 | |
} | |
function and(predA, predB) { | |
return (...args) => predA(...args) && predB(...args) | |
} | |
const always = v => () => v | |
const isNil = v => v == null | |
const isDivisibleByThree = isDivisibleBy(3) | |
const isDivisibleByFive = isDivisibleBy(5) | |
const isDivisibleByThreeAndFive = and(isDivisibleByThree, isDivisibleByFive) | |
function cond([pred, fn, ...cases]) { | |
if (isNil(pred)) | |
return always(undefined) | |
return (...args) => | |
pred(...args) | |
? fn(...args) | |
: cond(cases)(...args) | |
} | |
const otherwise = () => true | |
const identity = v => v | |
const fizzBuzz = cond([ | |
isDivisibleByThreeAndFive, always('FizzBuzz'), | |
isDivisibleByThree, always('Fizz'), | |
isDivisibleByFive, always('Buzz'), | |
otherwise, identity, | |
]) | |
console.log(times(fizzBuzz, 24)) | |
// transducers | |
const filterer = fn => reducer => | |
(acc, value) => fn(value) | |
? reducer(acc, value) | |
: acc | |
const mapper = fn => reducer => | |
(acc, value) => reducer(acc, fn(value)) | |
const reducer = (fn, seed) => _ => { | |
let first = true | |
return (acc, value) => { | |
if (first) { | |
first = false | |
return fn(seed, value) | |
} | |
return fn(acc, value) | |
} | |
} | |
const append = (acc, item) => [...acc, item] | |
function transduce(transducer, init, list) { | |
return list.reduce(transducer(append), init) | |
} | |
function pipe(fn, ...fns) { | |
if (isNil(fn)) | |
return identity | |
return (...args) => { | |
return pipe(...fns)(fn(...args)) | |
} | |
} | |
function compose(...fns) { | |
return pipe(...reverse(fns)) | |
} | |
function reverse([v, ...items], reversed = []) { | |
return isNil(v) | |
? reversed | |
: reverse(items, [v, ...reversed]) | |
} | |
function inc(n) { | |
return n + 1 | |
} | |
function isOdd(n) { | |
return n % 2 === 1 | |
} | |
function partial(fn, ...args) { | |
return (...more) => fn(...[...args, ...more]) | |
} | |
console.log( | |
transduce( | |
compose( | |
filterer(isOdd), | |
mapper(inc), | |
reducer(sum, 0) | |
), | |
[], | |
times(identity, 50) | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment