Last active
March 30, 2017 16:02
-
-
Save ChillyBwoy/1d933c298d5d199fa8b48ed43a4cbde7 to your computer and use it in GitHub Desktop.
Transducers JavaScript
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
class Reduced { | |
static isReduced(inst) { | |
return (inst instanceof Reduced); | |
} | |
constructor(wrapped) { | |
this._wrapped = wrapped; | |
} | |
unwrap() { | |
return this._wrapped; | |
} | |
} | |
function curryArgs() { | |
return (first) => (all) => (last) => (...args) => { | |
if (args.length === 0) { | |
return first(...args); | |
} | |
if (args.length === 1) { | |
return last(...args); | |
} | |
if (args.length === 2) { | |
return all(...args); | |
} | |
}; | |
} | |
function prepareArgs(first, all, last) { | |
return (...args) => { | |
if (args.length === 0) { | |
return first(...args); | |
} | |
if (args.length === 1) { | |
return last(...args); | |
} | |
if (args.length === 2) { | |
return all(...args); | |
} | |
}; | |
} | |
function reduce(collection, fn, seed) { | |
let result = seed; | |
for (let item of collection) { | |
result = fn(result, item); | |
if (Reduced.isReduced(result)) { | |
return result.unwrap(); | |
} | |
} | |
return result; | |
} | |
function append(result, item) { | |
if (arguments.length === 2) { | |
return result.concat([item]); | |
} | |
if (arguments.length === 1) { | |
return result; | |
} | |
if (arguments.length === 0) { | |
return []; | |
} | |
} | |
function transduce(collection, transducer, append) { | |
const step = transducer(append); | |
const seed = step(); | |
const result = reduce(collection, step, seed); | |
return step(result); | |
} | |
// transducers constructors: | |
function take(n) { | |
return (step) => { | |
let count = 0; | |
const onFirst = () => step(); | |
const onLast = result => step(result); | |
const onAll = (result, item) => { | |
if (count++ < n) { | |
return step(result, item); | |
} | |
return new Reduced(result); | |
}; | |
return prepareArgs(onFirst, onAll, onLast); | |
}; | |
} | |
function map(fn) { | |
return (step) => (...args) => { | |
if (args.length === 2) { | |
const [result, item] = args; | |
return step(result, fn(item)); | |
} | |
if (args.length === 1) { | |
const [result] = args; | |
return step(result); | |
} | |
if (args.length === 0) { | |
return step(); | |
} | |
}; | |
} | |
function filter(predicate) { | |
return (step) => { | |
const onFirst = () => step(); | |
const onLast = result => step(result); | |
const onAll = (result, item) => { | |
if (predicate(item)) { | |
return step(result, item); | |
} | |
return result; | |
}; | |
return prepareArgs(onFirst, onAll, onLast); | |
}; | |
} | |
function flatten() { | |
return (step) => { | |
const onFirst = () => step(); | |
const onLast = result => step(result); | |
const onAll = (result, item) => { | |
for (let i = 0; i < item.length; i++) { | |
result = step(result, item[i]); | |
} | |
return result; | |
}; | |
return prepareArgs(onFirst, onAll, onLast); | |
}; | |
} | |
function partition(n) { | |
if (n < 1) { | |
throw new Error("n > 1"); | |
} | |
return (step) => { | |
let current = []; | |
const onFirst = () => step(); | |
const onLast = result => { | |
if (current.length > 0) { | |
result = step(result, current); | |
return step(result); | |
} | |
}; | |
const onAll = (result, item) => { | |
current.push(item); | |
if (current.length === n) { | |
result = step(result, current); | |
current = []; | |
} | |
return result; | |
}; | |
return prepareArgs(onFirst, onAll, onLast); | |
}; | |
} | |
// sample | |
const initial = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; | |
const addOneT = map(x => x + 1); | |
const lessTnan4T = filter(x => x < 4); | |
const flattenT = flatten(); | |
const first5T = take(5); | |
const by3ItemsT = partition(3); | |
const addOne_lessTnan4 = (step) => addOneT(lessTnan4T(step)); | |
console.log(transduce(initial, addOneT, append)); | |
console.log(transduce(initial, lessTnan4T, append)); | |
console.log(transduce(initial, addOne_lessTnan4, append)); | |
console.log(transduce([[1, 2], [], [3]], flattenT, append)); | |
console.log(transduce(initial, first5T, append)); | |
console.log(transduce(initial, by3ItemsT, append)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment