【问题标题】:How to compose functions like zip-apply-ish如何编写诸如 zip-apply-ish 之类的函数
【发布时间】:2018-08-15 08:42:08
【问题描述】:

假设我有一堆 arity 2 的函数:f: a b -> xg: c d -> y, 等到一元函数u: a -> a。我想做的是以这样的方式链接它们:

f(_, g(_, .... z(_, u(_))...)

_ 占位符内,来自给定输入数组的连续值将被注入。我正在尝试使用Ramda 库来解决这个问题。

我遇到的另一个非常相似的问题是以相同的方式链接函数,但 _ 占位符填充了与执行此组合的相同值。

更具体:

// 1st problem
someComposition( f(v[0], g(v[1], ..... z(v[n-1], u(v[n]))...) )(v);

// 2nd problem
someComposition2( f(v, g(v, ..... z(v, u(v))...) )(v);

对于第二个问题,我能想到的最好的办法是,假设所有函数都是可治愈的,遵循一段代码(讨厌它,因为 (v) 重复):

compose(
    z(v),
    ...
    g(v),
    f(v),
    u
)(v);

我尝试使用composecomposeKpipeap 解决它,但它们似乎都不适用于这种情况,或者我只是无法看到解决方案。欢迎任何帮助。

【问题讨论】:

    标签: functional-programming ramda.js function-composition


    【解决方案1】:

    Ramda 中没有直接内置任何内容。 (免责声明:我是 Ramda 的作者之一。)如果你愿意,你可以创建这样的合成函数:

    const {tail, compose, reduce, identity, reverse} = R;
    
    const f = (x, y) => `f(${x}, ${y})`;
    const g = (x, y) => `g(${x}, ${y})`;
    const h = (x, y) => `h(${x}, ${y})`;
    const i = (x, y) => `i(${x}, ${y})`;
    const j = (x) => `j(${x})`;
    
    const multApply = (fns) => (...vals) => fns.length < 2 
          ? fns[0].apply(null, vals) 
          : fns[0](vals[0], multApply(tail(fns))(...tail(vals)));
    
    console.log(multApply([f, g, h, i, j])('a', 'b', 'c', 'd', 'e'));
                                   //=> f(a, g(b, h(c, i(d, j(e)))))
    
    const nest = compose(reduce((g, f) => (v) => f(v, g(v)), identity), reverse);
    
    console.log(nest([f, g, h, i, j])('v')) //=> f(v, g(v, h(v, i(v, j(v)))));
    &lt;script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"&gt;&lt;/script&gt;

    这些都不会对空列表或比函数列表短的参数列表(在第一种情况下)进行任何错误检查。但除此之外,它们似乎符合要求。

    肯定会有第二个的递归版本来匹配第一个,但是这个实现已经相当简单了。我没有看到第一个版本像第二个那样简单,但它很可能存在。

    【讨论】:

    • 感谢 Scott 的回答是没有像这样嵌入到库中;(
    【解决方案2】:

    可能有一些我不知道的方便的 Ramda 函数,或者一些我不明白的超级函数组合器让这变得简单,但无论如何:


    您可以创建自己的组合函数来组合二进制函数列表并注入值。这个函数接受一个函数列表和一个参数列表。它将获得的第一个函数部分应用到第一个参数并继续这样做,直到它没有参数,在此它返回一个最终的组合(一元)函数:

    // Utils
    const { add, subtract, multiply, identity, compose, isNil } = R;
    const square = x => x * x;
    
    // Our own compose method
    const comp2_1 = ([f2, ...f2s ], [x, ...xs], f = identity) =>
      isNil(x)
        ? compose(f2, f)
        : comp2_1(f2s, xs, compose(f2(x), f));
    
    
    // An example
    const myFormula = comp2_1(
      [add, subtract, multiply, square], 
      [10, 5, 2]);
    
    // 3 + 10 = 13
    // 13 - 5 = 8
    // 8 * 2 = 16
    // 16 * 16 = 256
    console.log(myFormula(3));
    &lt;script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"&gt;&lt;/script&gt;

    此示例仅适用于 xs.length === fs.length + 1。您可能希望它更灵活一些,例如,即使我们没有参数,也可以继续组合:

    /* ... */
    isNil(x)
      ? isNil(f2) 
        ? f
        : comp2_1(f2s, [], compose(f2, f)) 
      : /* ... */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-15
      相关资源
      最近更新 更多