代码之家  ›  专栏  ›  技术社区  ›  J. Hesters

如何使用ramda将代码从lisp(mit模式)转换为javascript?

  •  2
  • J. Hesters  · 技术社区  · 7 年前

    我目前正在自学函数式编程。

    我正在翻译以下内容:

    (define a 3)
    (define b (+ a 1))
    
    (* (cond ((> a b) a)
             ((< a b) b)
             (else -1))
       (+ a 1))
    

    变成javascript(使用ramda)。

    可以使用嵌套的三元,但我喜欢使用 cond Ramda的功能。以下是我所做的:

    const a = 3;
    const b = 3 + 1;
    
    cond([[() => a > b, () => a], [() => a < b, () => b], [T, () => -1]])() * (a + 1)
    

    我遇到的问题是我必须使用这些函数(例如 () => 3 )而不仅仅是它们的价值(例如 a )

    有什么方法可以避免这些功能吗?或者在javascript中是否有其他更好的方法(甚至没有rambda)?

    我想避免这样的陈述 if , for switch .

    解决这一问题的另一种方法是:

    import gt from "ramda/src/gt";
    import lt from "ramda/src/lt";
    
    const a = () => 3;
    const b = () => a() + 1;
    
    
    cond([[gt(a, b), a], [lt(a, b), b], [T, () => -1]])() * (a() + 1);
    

    使事情复杂化 b ,因为它们总是必须被调用(请参见 a() + 1 )

    编辑:

    出于某种原因,我定义的最后一个代码 因为功能不起作用

    3 回复  |  直到 7 年前
        1
  •  3
  •   Ori Drori    7 年前

    Ramda是自动循环的,因此您可以使用一些参数调用函数,并返回一个新的函数。例如:

    const { pipe, cond, gt, lt, T, always, identity, multiply } = R
    
    const a = 3
    const b = 3 + 1
    
    const fn = (a) => pipe(
      cond([
        [gt(a), always(a)],
        [lt(a), identity],
        [T, always(-1)]
      ]),
      multiply(a + 1)
    )
    
    const result = fn(a)(b)
    
    console.log(result)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
        2
  •  2
  •   Scott Sauyet    7 年前

    我觉得你工作有点误会。 cond 旨在为您提供一个功能。它实际上不是为表达式创建标量值而设计的。当然,它可以这样做,只需立即调用它生成的函数即可。但这不是重点。此外,它实际上并不用于使用空函数进行调用(传递的情况除外 T 对于默认条件)。同样,你也可以这样做,但它是在对抗工具的纹理。

    尽管ramda的灵感来源于lisp风格和ml风格的功能语言,而且我个人更喜欢前者,但是ramda更接近ml世界,尤其是haskell。因此,它要支持的主要活动是通过组合其他函数来构建函数。

    如果我要解决这个问题,我可能不会使用任何Ramda,选择这样的东西:

    const larger = (a, b) => (a > b) ? a : (b > a) ? b : -1
    const foo = (a, b) => (a + 1) * larger(a, b)
    
    foo(3, 4) //=> 16
    foo(6, 3) //=> 42
    foo(3, 3) //=> -4
    

    或者,如果我不需要重用 larger ,我可以这样内联它:

    const foo = (a, b) => (a + 1) * ((a > b) ? a : (b > a) ? b : -1)
    

    当然,我可以用Ramda和无点的方式写:

    const larger = cond([[gt, unapply(head)], [lt, unapply(last)], [T, always(-1)]])
    const foo = converge(multiply, [inc, larger])
    

    或者,我可能会插队 更大的 或替换 unapply(head) 具有 nthArg(0) unapply(last) 具有 nthArg(1) .

    但这些选项都不如原始选项可读。拉姆达没有在这里加任何我能看到的东西。请注意,我是Ramda的忠实粉丝;我创办了图书馆,并且是它的主要作者之一。但我不认为它应该适用于所有问题。

        3
  •  1
  •   steenuil    7 年前

    您不必在Scheme中用thunk(即不带参数的函数)包装所有内容的原因是 cond 是一个扩展到嵌套的宏 if S,在您的情况下:

    (if (> a b) a
      (if (< a b) b
        -1))
    

    所以不,如果你想避免三元运算符,并用thunk包装所有的东西,你就没有很多选择了香草JS。

    如果不介意使用非标准JS,可以实现 康德 使用宏 Sweet.js