代码之家  ›  专栏  ›  技术社区  ›  Andrew

javascript中的函数组合

  •  2
  • Andrew  · 技术社区  · 8 年前

    我知道这是很有可能的,因为我的haskell朋友似乎可以在他们的睡眠中做这种事情,但我不能用js来理解更复杂的函数组合。

    例如,假设您具有以下三个功能:

    const round = v => Math.round(v);
    
    const clamp = v => v < 1.3 ? 1.3 : v;
    
    const getScore = (iteration, factor) =>
        iteration < 2 ? 1 :
        iteration === 2 ? 6 :
        (getScore(iteration - 1, factor) * factor);
    

    在这种情况下,比如 iteration 应该是整数,因此我们希望应用 round() 为了这个论点。想象一下 factor 必须至少是 1.3 ,所以我们想申请 clamp() 为了这个论点。

    如果我们打破 getScore 分为两个功能,这似乎更容易组合:

    const getScore = iteration => factor =>
        iteration < 2 ? 1 :
        iteration === 2 ? 6 :
        (getScore(iteration - 1)(factor) * factor);
    

    执行此操作的代码可能如下所示:

    const getRoundedClampedScore = compose(round, clamp, getScore);
    

    但是compose函数是什么样子的呢怎么样 getRoundedClampedScore 调用?或者这是一个可怕的错误?

    3 回复  |  直到 8 年前
        1
  •  3
  •   CertainPerformance    8 年前

    这个 compose 函数应该取核心函数 第一 ,使用rest参数将其他函数放入数组中,然后返回一个调用 i 数组中的th函数 第四个参数:

    const round = v => Math.round(v);
    
    const clamp = v => v < 1.3 ? 1.3 : v;
    
    const getScore = iteration => factor =>
        iteration < 2 ? 1 :
        iteration === 2 ? 6 :
        (getScore(iteration - 1)(factor) * factor);
    
    const compose = (fn, ...transformArgsFns) => (...args) => {
      const newArgs = transformArgsFns.map((tranformArgFn, i) => tranformArgFn(args[i]));
      return fn(...newArgs);
    }
    
    const getRoundedClampedScore = compose(getScore, round, clamp);
    
    console.log(getRoundedClampedScore(1)(5))
    console.log(getRoundedClampedScore(3.3)(5))
    console.log(getRoundedClampedScore(3.3)(1))
        2
  •  3
  •   Aadit M Shah    8 年前

    haskell程序员通常可以简化表达式,类似于简化数学表达式的方式。我将在这个答案中告诉你怎么做首先,让我们看看你的表达式的构造块:

    round    :: Number -> Number
    clamp    :: Number -> Number
    getScore :: Number -> Number -> Number
    

    通过组合这三个函数,我们希望创建以下函数:

    getRoundedClampedScore :: Number -> Number -> Number
    getRoundedClampedScore iteration factor = getScore (round iteration) (clamp factor)
    

    我们可以将这个表达式简化如下:

    getRoundedClampedScore iteration factor = getScore (round iteration) (clamp factor)
    getRoundedClampedScore iteration        = getScore (round iteration) . clamp
    getRoundedClampedScore iteration        = (getScore . round) iteration . clamp
    getRoundedClampedScore iteration        = (. clamp) ((getScore . round) iteration)
    getRoundedClampedScore                  = (. clamp) . (getScore . round)
    getRoundedClampedScore                  = (. clamp) . getScore . round
    

    如果要将其直接转换为JavaScript,则可以使用反向函数组合:

    const pipe = f => g => x => g(f(x));
    
    const compose2 = (f, g, h) => pipe(g)(pipe(f)(pipe(h)));
    
    const getRoundedClampedScore = compose2(getScore, round, clamp);
    
    // You'd call it as follows:
    
    getRoundedClampedScore(iteration)(factor);
    

    也就是说,最好的解决方案是简单地以有意义的形式定义它:

    const compose2 = (f, g, h) => x => y => f(g(x))(h(y));
    
    const getRoundedClampedScore = compose2(getScore, round, clamp);
    

    Pointfree style 通常有用,但有时毫无意义。

        3
  •  3
  •   JLRishe    8 年前

    我想你的部分麻烦是 compose 不是你要找的功能,而是别的。 组成 通过一系列函数提供值,而您希望预先处理一系列参数,然后将这些处理过的参数提供给最终函数。

    Ramda 有一个非常适合的实用函数,叫做 converge 是的。什么 汇聚 does是生成一个函数,该函数将一系列函数应用于1对1对应的一系列参数,然后将所有这些转换的参数馈送到另一个函数中。在您的情况下,使用它将如下所示:

    var saferGetScore = R.converge(getScore, [round, clamp]);
    

    如果你不想参与整个第三方图书馆的工作 汇聚 函数,您可以用一行代码轻松定义。它看起来很像CaptainPerformance在他们的回答中使用的功能,但是少了一个 ... (你绝对不应该说出它的名字 组成 ,因为这是一个完全不同的概念):

    const converge = (f, fs) => (...args) => f(...args.map((a, i) => fs[i](a)));
    
    const saferGetScore = converge(getScore, [round, clamp]);
    const score = saferGetScore(2.5, 0.3);
    
    推荐文章