【问题标题】:Order of Execution of Composed Function组合函数的执行顺序
【发布时间】:2017-11-27 00:39:20
【问题描述】:

我一直在阅读有关传感器的信息,并尝试掌握这个概念。我现在有点理解它们了,但是在我摆弄的过程中,我遇到了一些非常奇怪的东西,让我目瞪口呆。我希望有人能解释我错过了什么。

我有 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]

【问题讨论】:

  • 也许单步调试器?
  • 我怀疑没有办法简化代码——它已经被简化了。比如上面filterLessThanThreeAndMultiply的定义比写成这样简单:const filterLessThanThreeAndMultiply = filteringReducer(lessThanThreePredicate)(mappingReducer(multiplyTransform))
  • 我不想简化代码。我试图理解为什么执行顺序似乎与 compose 函数所建议的相反。

标签: javascript transducer


【解决方案1】:

您看到filter(正确)发生在map 之前,即使它们都在compose 内部,因为transducers 的实现细节。我将通过分解实现中的传感器进行解释,然后向您展示如何使用它们。

考虑mapfilter 的以下变体

const 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
  1. mapArray 接受一个函数 fn 和一个数组,然后返回另一个数组,其中 fn 应用于每个元素。
  2. filterArray 接受一个函数 fn 和一个数组并返回另一个由 fn 过滤的数组
  3. mapReducer 接受一个函数 fn 并返回 reducer =&gt; (y, xi) =&gt; {...}
  4. filterReducer 接受一个函数 fn 并返回 reducer =&gt; (y, xi) =&gt; {...}

现在,考虑传感器签名

transducers 有签名:reducer -> reducer

鉴于(y, xi) =&gt; {...} 只是另一个reducer,这意味着mapReducer(multiplyTransform)filterReducer(lessThanThreePredicate) 都是transducer

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

展览 A(无作曲)

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]

为了设置我们的传感器,以便我们首先过滤x =&gt; x &lt; 3,然后映射x =&gt; x * 100,我们必须像上面那样组合我们的传感器lessThanThreeTransducerx100Transducer。现在,如果我们输入compose,您就会知道为什么一切似乎都倒退了。

展览 B(带撰写)

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]

确实,finalComposedReducerfinalReducerLessThanThreeThenX100ThenConcat 在算法上是等效的。那么,

为什么??!!

这是一个转换器的实现细节。如果你仍然对传感器感到好奇,我会写更多关于它们的文章here

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 2015-11-09
    • 2016-04-07
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多