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

你能给我一个如何使用拉姆达电梯的例子吗?

  •  6
  • Adam  · 技术社区  · 7 年前

    我在看拉姆达文件

    const madd3 = R.lift((a, b, c) => a + b + c);
    
    madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
    

    它看起来是一个非常有用的函数。我不知道它的用例是什么。

    谢谢

    4 回复  |  直到 7 年前
        1
  •  1
  •   customcommander    7 年前

    此函数只能接受数字:

    const add3 = (a, b, c) => a + b + c;
    add3(1, 2, 3); //=> 6
    

    但是,如果这些数字都包含在一个函数中呢? (即包含一个值的事物;下面示例中的数组)

    add3([1], [2], [3]); //=> "123"
    

    这显然不是我们想要的。 您可以“提升”函数,以便它可以“提取”每个参数/函数的值:

    const add3Lifted = lift(add3);
    add3Lifted([1], [2], [3]); //=> [6]
    

    很明显,数组可以保存多个值,并与一个提升函数结合使用,该函数知道如何提取每个函数的值,现在可以这样做:

    add3Lifted([1, 10], [2, 20], [3, 30]);
    //=> [6, 33, 24, 51, 15, 42, 33, 60]
    

    如果你这样做了,基本上你会得到:

    [
      add3(1, 2, 3),    // 6
      add3(1, 2, 30),   // 33
      add3(1, 20, 3),   // 24
      add3(1, 20, 30),  // 51
      add3(10, 2, 3),   // 15
      add3(10, 2, 30),  // 42
      add3(10, 20, 3),  // 33
      add3(10, 20, 30)  // 60
    ]
    

    请注意,每个数组的长度不必相同:

    add3Lifted([1, 10], [2], [3]);
    //=> [6, 15]
    

    因此,要回答您的问题:如果您打算运行一个具有不同值集的函数,那么提升该函数可能是一个需要考虑的有用的事情:

    const results = [add3(1, 2, 3), add3(10, 2, 3)];
    

    相同:

    const results = add3Lifted([1, 10], [2], [3]);
    
        2
  •  2
  •   Scott Christopher    7 年前

    当前答案中没有提到的是 R.lift 不仅可以使用数组,还可以使用任何行为良好的 Apply 一 数据类型。

    例如,我们可以重用 升降机 :

    const lifted = lift((a, b, c) => a + b - c)
    

    函数作为应用类型:

    lifted(a => a * a,
           b => b + 5,
           c => c * 3)(4) //=> 13
    

    可选类型(发送至 .ap ):

    const Just = val => ({
      map: f    => Just(f(val)),
      ap: other => other.map(otherVal => val(otherVal)),
      getOr: _  => val
    })
    
    const Nothing = {
      map: f    => Nothing,
      ap: other => Nothing,
      getOr: x  => x
    }
    
    lifted(Just(4), Just(6), Just(8)).getOr(NaN) //=> 2
    
    lifted(Just(4), Nothing, Just(8)).getOr(NaN) //=> NaN
    

    异步类型(调度到 美联社 ):

    const Asynchronous = fn => ({
      run: fn,
      map: f    => Asynchronous(g => fn(a => g(f(a)))),
      ap: other => Asynchronous(fb => fn(f => other.run(a => fb(f(a)))))
    })
    
    const delay = (n, x) => Asynchronous(then => void(setTimeout(then, n, x)))
    
    lifted(delay(2000, 4), delay(1000, 6), delay(500, 8)).run(console.log)
    

    …还有更多。这里的要点是,任何能够支持接口和任何应用类型的预期规则的东西都可以使用通用函数,例如 升降机 .

    1。论证顺序 ap 如Fantasy Land规范中所列,与Ramda中名称调度支持的顺序相反,但在使用 fantasy-land/ap 命名空间方法。

        3
  •  2
  •   David Lemon amitgoyal    7 年前

    函数编程是一个很长的数学主题,尤其是 the part dealing with monads 和 cathegory theory in general . 但值得一看, here is a funny introduction with pictures .

    简而言之,电梯需要 n元 函数并生成一个函数 n 包裹值 产生另一个结果 包装价值 .

    这个 包装价值 是一个实用的 Functor 从现在开始,我称之为应用性。

    也许你从这一点开始失去了兴趣,但我们之前的某个人在这个问题上已经失去了兴趣, finally he survived and published it as an answer to this question . 让我们看看他看到了什么…

    …

    What did you see? (xkcd comic)

    他看到了梦幻之地

    在幻想世界里,一个物体实现 Apply 当它有 安 ap 定义的方法(该对象还必须实现 Functor 通过定义 map 方法)。

    • Fantasy Land是函数式编程规范中的一个花哨名称。 JavaScript。拉姆达跟着它。
    • 应用是我们的应用,一个 函子 它还实现了 AP 方法。
    • 一 函子 ,是指 地图 方法。

    所以,等等…javascript中的数组有一个映射…

    [1,2,3].map((a)=>a+1) \\=> [ 2, 3, 4 ]
    

    然后数组是一个函数,map将一个函数应用于它的所有值,返回另一个具有相同数值的函数。

    但是什么是 ap 怎么办?

    AP将函数列表应用于值列表。

    发送到第二个参数的ap方法(如果存在)。阿尔索 将课程功能视为应用。

    让我们试着用它做点什么。

    const res = R.ap(
      [
        (a)=>(-1*a), 
        (a)=>((a>1?'greater than 1':'a low value'))
      ], 
      [1,2,3]); //=>  [ -1, -2, -3, "a low value", "greater than 1", "greater than 1" ]
    
    console.log(res);
    <script src="https://cdn.jsdelivr.net/npm/ramda@0.26.1/dist/ramda.min.js"></script>

    ap方法获取一个函数数组(或其他应用程序),并将其应用于值的应用程序,以生成另一个应用程序展平。

    方法的签名解释了这一点

    [a → b] → [a] → [b]
    Apply f => f (a → b) → f a → f b
    

    最后,电梯是做什么的?

    电梯的功能 n 参数,并生成另一个函数 n 副词 产生一个扁平的 补语的 结果。

    在这种情况下,我们的应用程序是数组。

    const add2 = (a, b) => a + b;
    const madd2 = R.lift(add2);
    
    const res = madd2([1,2,3], [2,3,4]); 
    //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
    
    console.log(res);
    // Equivalent to lift using ap
    const result2 = R.ap(R.ap(
      [R.curry(add2)], [1, 2, 3]),
      [2, 3, 4]
      );
    //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
    console.log(result2);
    <script src=“https://cdn.jsdelivr.net/npm/ramda@0.26.1/dist/ramda.min.js”></script>

    这些 包装纸 (应用程序、函数、monad)很有趣,因为它们可以是实现这些方法的任何东西。在haskell中,这用于包装不安全的操作,如输入/输出。它也可以是错误包装器或树,甚至是任何数据结构。

        4
  •  1
  •   Nina Scholz    7 年前

    基本上,它采用笛卡尔积,并对每个数组应用一个函数。

    const
        cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
        fn = ([a, b, c]) => a + b + c,
        result = [[1, 2, 3], [1, 2, 3], [1]]
            .reduce(cartesian)
            .map(fn);
    
    console.log(result); // [3, 4, 5, 4, 5, 6, 5, 6, 7]
    推荐文章