如何使用 Ramda 将代码从 Lisp (MIT Schema) 翻译成 JavaScript?
How to translate code from Lisp (MIT Schema) into JavaScript using Ramda?
我目前正在自学函数式编程。
我正在尝试翻译以下内容:
(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
)。
有什么办法可以避免这些功能吗?或者在 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);
这使 a
和 b
变得复杂,因为它们总是必须被调用(参见 a() + 1
)。
编辑:
出于某种原因,我将 a
和 b
定义为函数的最后一段代码不起作用
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>
在 Scheme 中不必将所有内容都包装在 thunk(即不带参数的函数)中的原因是因为 cond
是一个扩展为嵌套 if
的宏,在你的情况:
(if (> a b) a
(if (< a b) b
-1))
所以不,如果你想避免三元运算符并将所有内容包装在 thunk 中,你对 vanilla JS 没有太多选择。
如果您不介意使用非标准 JS,您可以使用 Sweet.js...
的宏来实现 cond
我认为您是在有点误解的情况下工作的。 cond
旨在给你一个功能。它实际上不是为为表达式创建标量值而设计的。它当然可以这样做,只需立即调用它生成的函数即可。但这不是重点。此外,它实际上并不意味着使用空函数进行调用(默认情况下传递 T
的情况除外。)。同样,您可以这样做,但它违背了该工具的宗旨。
尽管 Ramda 从 LISP 风格和 ML 风格的函数式语言中汲取灵感,虽然我个人更喜欢前者,但 Ramda 更接近 ML 世界,尤其是 Haskell。所以它主要activity支持的是通过组合其他函数来构建函数。
如果我要解决这个问题,我可能不会使用任何 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)
。
但是 none 这些选项与原始选项一样可读。 Ramda 在这里没有添加任何我能看到的内容。请注意,我是 Ramda 的忠实粉丝;我创办了这个图书馆,并且是它的主要作者之一。但我不认为它应该用于所有问题。
我目前正在自学函数式编程。
我正在尝试翻译以下内容:
(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
)。
有什么办法可以避免这些功能吗?或者在 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);
这使 a
和 b
变得复杂,因为它们总是必须被调用(参见 a() + 1
)。
编辑:
出于某种原因,我将 a
和 b
定义为函数的最后一段代码不起作用
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>
在 Scheme 中不必将所有内容都包装在 thunk(即不带参数的函数)中的原因是因为 cond
是一个扩展为嵌套 if
的宏,在你的情况:
(if (> a b) a
(if (< a b) b
-1))
所以不,如果你想避免三元运算符并将所有内容包装在 thunk 中,你对 vanilla JS 没有太多选择。
如果您不介意使用非标准 JS,您可以使用 Sweet.js...
的宏来实现cond
我认为您是在有点误解的情况下工作的。 cond
旨在给你一个功能。它实际上不是为为表达式创建标量值而设计的。它当然可以这样做,只需立即调用它生成的函数即可。但这不是重点。此外,它实际上并不意味着使用空函数进行调用(默认情况下传递 T
的情况除外。)。同样,您可以这样做,但它违背了该工具的宗旨。
尽管 Ramda 从 LISP 风格和 ML 风格的函数式语言中汲取灵感,虽然我个人更喜欢前者,但 Ramda 更接近 ML 世界,尤其是 Haskell。所以它主要activity支持的是通过组合其他函数来构建函数。
如果我要解决这个问题,我可能不会使用任何 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)
。
但是 none 这些选项与原始选项一样可读。 Ramda 在这里没有添加任何我能看到的内容。请注意,我是 Ramda 的忠实粉丝;我创办了这个图书馆,并且是它的主要作者之一。但我不认为它应该用于所有问题。