如何使用Ramda将代码从Lisp(MIT模式)转换为JavaScript?

时间:2019-01-10 13:02:43

标签: javascript functional-programming lisp ramda.js mit-scheme

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

我正在尝试翻译以下内容:

(define a 3)
(define b (+ a 1))

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

进入JavaScript(使用Ramda)。

一个人可以使用嵌套三元组,但是我喜欢使用Ramda的cond函数。这是我所做的:

const a = 3;
const b = 3 + 1;

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

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

有什么办法可以避免这些功能?还是有另一种更好的方法(甚至没有Rambda)在JavaScript中做到这一点?

我想避免使用诸如ifforswitch之类的语句。

解决此问题的另一种方法是使用:

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);

ab较为复杂,因为它们总是必须被调用(请参阅a() + 1)。

编辑:

由于某种原因,我将ab定义为函数的最后一个代码不起作用

3 个答案:

答案 0 :(得分:3)

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>

答案 1 :(得分:2)

我认为您的工作有点误会。 cond旨在为您提供功能。它实际上不是为创建表达式的标量值而设计的。当然,只需立即调用它生成的函数就可以做到这一点。但这不是重点。而且,它实际上并不意味着要使用null函数进行调用(除非为默认条件传递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])

或者再次,我可以内联larger,或将unapply(head)替换为nthArg(0),将unapply(last)替换为nthArg(1)

但是这些选项都不比原始选项可读性高。 Ramda在这里看不到任何内容。请注意,我是Ramda的忠实粉丝;我创办了图书馆,是图书馆的主要作者之一。但我认为不应将其用于所有问题。

答案 2 :(得分:1)

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

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

所以没有,如果您想避免三元运算符并将所有内容包装在thunk中,那么使用香草JS就没有太多选择。

如果您不介意使用非标准JS,则可以使用带有Sweet.js ...的宏来实现cond