组合函数的执行顺序

时间:2017-11-27 00:39:21

标签: javascript transducer

我一直在读传感器并试图掌握这个概念。我现在对它们了解了一点,但在我摆弄的过程中,我遇到了一些让我目瞪口呆的特别奇怪的东西。我希望有人可以解释我失踪的东西。

我有2个具有签名的传感器:reducer -> reducer

我还有一个简单的撰写函数:const compose = (f, g) => x => f(g(x))

当我组成2个传感器时:

const filterLessThanThreeAndMultiply = compose(
  filteringReducer(lessThanThreePredicate),
  mappingReducer(multiplyTransform)
)

我希望评估是从右到左,在这种情况下,在过滤之前应用映射变换。相反,首先应用过滤(这给出了预期的答案)。

但是f(g(x))运行g(x)的结果f,所以我的结果应该反映出来:

filteringReducer(lessThanThreePredicate)(mappingReducer(multiplyTransform)
(concatTransducer))

但它反映(正确):

mappingReducer(multiplyTransform)(filteringReducer(lessThanThreePredicate)
(concatTransducer))

(见下面的代码)

为什么?? !! (我怀疑,一旦有人向我解释这里发生的事情,我会在理解上有一个巨大的飞跃。)

const filteringReducer = predicate => transducer => (result, input) =>
  predicate(input) ? transducer(result, input) : result

const mappingReducer = transform => transducer => (result, input) =>
  transducer(result, transform(input))

const compose = (f, g) => x => f(g(x))

const concatTransducer = (a, b) => a.concat([b])

const lessThanThreePredicate = x => x < 3
const multiplyTransform = x => x * 100

const filterLessThanThreeAndMultiply = compose(
  filteringReducer(lessThanThreePredicate),
  mappingReducer(multiplyTransform)
)

const result = [-2, -1, 0, 1, 2, 3, 4].reduce(
  filterLessThanThreeAndMultiply(concatTransducer),
  []
)

console.log('result ', result)  // [-200, -100, 0, 100, 200]

1 个答案:

答案 0 :(得分:0)

由于换能器的实现细节,即使filter都在map内,您仍看到compose发生在map之前。我将通过分解实现中的换能器,然后向您展示如何使用它们来进行解释。

请考虑以下filterconst mapArray = fn => array => array.map(fn) // map for arrays const filterArray = fn => array => array.filter(fn) // filter for arrays const mapReducer = fn => reducer => (y, xi) => reducer(y, fn(xi)) // map for reducers const filterReducer = fn => reducer => (y, xi) => fn(xi) ? reducer(y, xi) : y // filter for reducers 的变体

mapArray
  1. fn接受一个函数fn和一个数组,并返回另一个将filterArray应用于每个元素的数组。
  2. fn接受一个函数fn和一个数组,并返回由mapReducer过滤的另一个数组
  3. fn使用函数reducer => (y, xi) => {...}并返回filterReducer
  4. fn使用函数reducer => (y, xi) => {...}并返回(y, xi) => {...}

现在,考虑换能器签名

换能器具有签名:reducer-> reducer

给出mapReducer(multiplyTransform)只是另一个简化器,这意味着filterReducer(lessThanThreePredicate)const x100Transducer = mapReducer(x => x * 100) const lessThanThreeTransducer = filterReducer(x => x < 3) const concat = (y, xi) => y.concat([xi]) const finalReducerLessThanThreeThenX100ThenConcat = (y, xi) => ( lessThanThreeTransducer( // this is called with (y, xi) first x100Transducer( // then this concat // finally this ) )(y, xi) ) [1, 2, 3, 4, 5].reduce(finalReducerX100ThenConcat, []) // => [100, 200] 都是换能器

太好了!所以现在我们知道什么是换能器,但是我们如何使用它们呢?

展览A(无内容)

x => x < 3

为了设置传感器,以便我们首先过滤x => x * 100然后映射lessThanThreeTransducer,我们必须像上面所做的那样组成传感器x100Transducercompose 。现在,如果我们折腾const x100Transducer = mapReducer(x => x * 100) const lessThanThreeTransducer = filterReducer(x => x < 3) const concat = (y, xi) => y.concat([xi]) const compose = (f, g) => x => f(g(x)) // f is lessThanThreeTransducer, g is x100Transducer // x is concat (compare to above) const finalComposedReducer = compose(lessThanThreeTransducer, x100Transducer)(concat) [1, 2, 3, 4, 5].reduce(finalComposedReducer, []) // => [100, 200] ,您将得到为什么一切看起来都倒退的答案。

展览B(含撰写)

finalComposedReducer

实际上,finalReducerLessThanThreeThenX100ThenConcat和{{1}}在算法上是等效的。所以,

为什么?? !!

这是换能器的实现细节。如果您仍然对换能器感到好奇,请写更多关于换能器的here