reducible
Version:
High-order abstraction for reducible data structures
60 lines (48 loc) • 1.98 kB
JavaScript
;
var method = require("method")
var isReduced = require("./is-reduced")
var isError = require("./is-error")
var end = require("./end")
var reduce = method("reduce@reducible")
// Implementation of `reduce` for the empty collections, that immediately
// signals reducer that it's ended.
reduce.empty = function reduceEmpty(empty, next, initial) {
next(end, initial)
}
// Implementation of `reduce` for the singular values which are treated
// as collections with a single element. Yields a value and signals the end.
reduce.singular = function reduceSingular(value, next, initial) {
next(end, next(value, initial))
}
// Implementation of `reduce` for the array (and alike) values, such that it
// will call accumulator function `next` each time with next item and
// accumulated state until it's exhausted or `next` returns marked value
// indicating that it's reduced. Either way signals `end` to an accumulator.
reduce.indexed = function reduceIndexed(indexed, next, initial) {
var state = initial
var index = 0
var count = indexed.length
while (index < count) {
var value = indexed[index]
state = next(value, state)
index = index + 1
if (value === end) return end
if (isError(value)) return state
if (isReduced(state)) return state.value
}
next(end, state)
}
// Both `undefined` and `null` implement accumulate for empty sequences.
reduce.define(void(0), reduce.empty)
reduce.define(null, reduce.empty)
// Array and arguments implement accumulate for indexed sequences.
reduce.define(Array, reduce.indexed)
function Arguments() { return arguments }
Arguments.prototype = Arguments()
reduce.define(Arguments, reduce.indexed)
// All other built-in data types are treated as single value collections
// by default. Of course individual types may choose to override that.
reduce.define(reduce.singular)
// Errors just yield that error.
reduce.define(Error, function(error, next) { next(error) })
module.exports = reduce