Last active
March 30, 2017 14:55
-
-
Save ChillyBwoy/fa8ac636396c78c36dd2 to your computer and use it in GitHub Desktop.
Transducers CoffeeScript
This file contains hidden or 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 | |
| @isReduced = (obj) -> obj instanceof Reduced | |
| constructor: (@wraped) -> | |
| unwrap: -> @wraped | |
| reduce = (collection, fn, seed) -> | |
| result = seed; | |
| for item in collection | |
| result = fn result, item | |
| if Reduced.isReduced result then return result.unwrap() | |
| return result | |
| append = (result, item) -> | |
| return [] if not result? and not item? | |
| return result if result? and not item? | |
| return result.concat [item] if result? and item? | |
| transduce = (collection, transducer, append) -> | |
| step = transducer append | |
| seed = step() | |
| result = reduce collection, step, seed | |
| return step result | |
| # constructors | |
| map = (fn) -> (step) -> (result, item) -> | |
| return step() if not result? and not item? | |
| return step(result) if result? and not item? | |
| return step(result, fn(item)) if result? and item? | |
| filter = (predicate) -> (step) -> (result, item) -> | |
| return (if predicate item then step result, item else result) if result? and item? | |
| return step(result) if result? and not item? | |
| return step() if not result? and not item? | |
| take = (n) -> (step) -> | |
| count = 0 | |
| (result, item) -> | |
| return (if count++ < n then step result, item else new Reduced result) if result? and item? | |
| return step(result) if result? and not item? | |
| return step() if not result? and not item? | |
| flatten = -> (step) -> (result, item) -> | |
| if result? and item? | |
| for x in item | |
| result = step result, x | |
| return result | |
| return step(result) if result? and not item? | |
| return step() if not result? and not item? | |
| partition = (n) -> | |
| if n < 1 then throw new Error "n > 1" | |
| (step) -> | |
| current = [] | |
| (result, item) -> | |
| if result? and item? | |
| current.push item | |
| if current.length is n | |
| result = step result, current | |
| current = [] | |
| return result | |
| if result? and not item? | |
| if current.length > 0 | |
| result = step result, current | |
| return result | |
| if not result? and not item? | |
| return step() | |
| # samples | |
| addOneT = map (x) -> x + 1 | |
| mulTwoT = map (x) -> x * 2 | |
| lessTnan4T = filter (x) -> x < 4 | |
| flattenT = flatten() | |
| first5T = take 5 | |
| by3ItemsT = partition 3 | |
| addOneMulTwoT = (step) -> addOneT mulTwoT(step) | |
| console.log(transduce [1..20], addOneT, append) | |
| console.log(transduce [1..20], mulTwoT, append) | |
| console.log(transduce [1..20], addOneMulTwoT, append) | |
| console.log(transduce [[1, 2], [], [3], [4, 5]], flattenT, append) | |
| console.log(transduce [1..20], lessTnan4T, append) | |
| console.log(transduce [1..20], first5T, append) | |
| console.log(transduce [1..20], by3ItemsT, append) |
This file contains hidden or 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
| "use strict"; | |
| function Reduced(wrapped) { | |
| this._wrapped = wrapped; | |
| } | |
| Reduced.isReduced = function(obj) { | |
| return (obj instanceof Reduced); | |
| }; | |
| Reduced.prototype.unwrap = function() { | |
| return this._wrapped; | |
| }; | |
| function curryArgs() { | |
| return function(first) { | |
| return function(all) { | |
| return function(last) { | |
| return function() { | |
| var args = Array.prototype.slice.call(arguments, 0); | |
| if (arguments.length === 0) { | |
| return first.apply(null, args); | |
| } | |
| if (arguments.length === 1) { | |
| return last.apply(null, args); | |
| } | |
| if (arguments.length === 2) { | |
| return all.apply(null, args); | |
| } | |
| }; | |
| }; | |
| }; | |
| }; | |
| } | |
| function prepareArgs(first, all, last) { | |
| return function() { | |
| var args = Array.prototype.slice.call(arguments, 0); | |
| if (arguments.length === 0) { | |
| return first.apply(this, args); | |
| } | |
| if (arguments.length === 1) { | |
| return last.apply(this, args); | |
| } | |
| if (arguments.length === 2) { | |
| return all.apply(this, args); | |
| } | |
| }; | |
| } | |
| function reduce(collection, fn, seed) { | |
| var result = seed; | |
| for (var i = 0; i < collection.length; i++) { | |
| result = fn(result, collection[i]); | |
| 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) { | |
| var step = transducer(append), | |
| seed = step(), | |
| result = reduce(collection, step, seed); | |
| return step(result); | |
| } | |
| // transducers constructors: | |
| function take(n) { | |
| return function(step) { | |
| var count = 0, | |
| onFirst = function() { return step(); }, | |
| onLast = function(result) { return step(result); }, | |
| onAll = function(result, item) { | |
| if (count++ < n) { | |
| return step(result, item); | |
| } else { | |
| return new Reduced(result); | |
| } | |
| }; | |
| return prepareArgs(onFirst, onAll, onLast); | |
| }; | |
| } | |
| function map(fn) { | |
| return function(step) { | |
| return function(result, item) { | |
| if (arguments.length === 2) { | |
| return step(result, fn(item)); | |
| } | |
| if (arguments.length === 1) { | |
| return step(result); | |
| } | |
| if (arguments.length === 0) { | |
| return step(); | |
| } | |
| }; | |
| }; | |
| } | |
| function filter(predicate) { | |
| return function(step) { | |
| var onFirst = function() { return step(); }, | |
| onLast = function(result) { return step(result); }, | |
| onAll = function(result, item) { | |
| if (predicate(item)) { | |
| return step(result, item); | |
| } else { | |
| return result; | |
| } | |
| }; | |
| return prepareArgs(onFirst, onAll, onLast); | |
| }; | |
| } | |
| function flatten() { | |
| return function(step) { | |
| var onFirst = function() { return step(); }, | |
| onLast = function(result) { return step(result); }, | |
| onAll = function(result, item) { | |
| for (var 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 function(step) { | |
| var current = [], | |
| onFirst = function() { return step(); }, | |
| onLast = function(result) { | |
| if (current.length > 0) { | |
| result = step(result, current); | |
| return step(result); | |
| } | |
| }, | |
| onAll = function(result, item) { | |
| current.push(item); | |
| if (current.length === n) { | |
| result = step(result, current); | |
| current = []; | |
| } | |
| return result; | |
| }; | |
| return prepareArgs(onFirst, onAll, onLast); | |
| }; | |
| } | |
| // sample | |
| var initial = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, | |
| 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; | |
| var addOneT = map(function(x) { return x + 1; }), | |
| lessTnan4T = filter(function(x) { return x < 4; }), | |
| flattenT = flatten(), | |
| first5T = take(5), | |
| by3ItemsT = partition(3); | |
| var addOne_lessTnan4 = function(step) { | |
| return 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