简体   繁体   English

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

[英]How to translate code from Lisp (MIT Schema) into JavaScript using Ramda?

I'm currently teaching myself functional programming. 我目前正在自学函数式编程。

I'm trying to translate the following: 我正在尝试翻译以下内容:

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

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

into JavaScript (using Ramda). 到JavaScript中(使用Ramda)。

One could use nested ternaries, but I like to using the cond function from Ramda. 一个可以使用嵌套的三元组,但是我喜欢使用Ramda的cond函数。 Here is what I did: 这是我所做的:

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

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

The problem I have with this is that I had to use these functions (eg () => 3 ) instead of just their value (eg a ). 我的问题是我不得不使用这些函数(例如() => 3 ),而不仅仅是它们的值(例如a )。

Is there any way to avoid these functions? 有什么办法可以避免这些功能? Or is there another better way of doing this in JavaScript (maybe even without Rambda)? 还是在JavaScript中有另一种更好的方法(甚至没有Rambda)?

I would like to avoid statements such as if , for and switch . 我想避免使用诸如ifforswitch类的语句。

An alternative way to solve this would be using: 解决此问题的另一种方法是使用:

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

Which complicates a and b , since they will always have to be called (see a() + 1 ). 这使ab变得复杂,因为将始终必须调用它们(请参阅a() + 1 )。

EDIT: 编辑:

For some reason the last code where I define a and b as functions doesn't work 🤔 由于某种原因,我定义ab为函数的最后一个代码不起作用doesn

Ramda is auto curried, so you can invoke the function with some of the parameters, and get a new function back. Ramda是自动管理的,因此您可以使用某些参数来调用该函数,并重新获得一个新函数。 For example: 例如:

 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> 

I think you're working under a bit of a misapprehension. 我认为您的工作有点误会。 cond is designed to give you a function. cond旨在为您提供功能。 It's really not designed for creating a scalar value for an expression. 它实际上不是为创建表达式的标量值而设计的。 Of course it can do so, simply by immediately calling the function it generates. 当然,只需立即调用它生成的函数就可以做到这一点。 But that's not the point of it. 但这不是重点。 Moreover, it really is not meant for calling with nullary functions (except in the case of passing T for the default condition.). 此外,它实际上并不意味着要使用空函数进行调用(默认情况下传递T的情况除外)。 Again, you can do so, but it's working against the grain of the tool. 同样,您可以执行此操作,但是这样做不利于工具的发展。

Although Ramda takes inspiration from both LISP-style and ML-style functional languages, and although I am personally more a fan of the former, Ramda is closer to the ML world, especially to Haskell. 尽管Ramda从LISP风格和ML风格的功能语言中汲取了灵感,并且尽管我个人更喜欢前者,但Ramda更接近ML世界,尤其是Haskell。 So the main activity it is meant to support is to build functions by composing other functions. 因此,它旨在支持的主要活动是通过组合其他功能来构建功能。

If I were to solve this problem, I probably wouldn't use any Ramda whatsoever, choosing something like this: 如果要解决此问题,则可能不会使用任何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

Or, if I didn't need to reuse larger , I might inline it like this: 或者,如果我不需要重用larger ,则可以像这样内联:

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

Of course I can write this in Ramda, and in a point-free fashion: 当然,我可以用Ramda编写这种代码,并且毫无意义:

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

Or again, I might inline larger , or replace unapply(head) with nthArg(0) and unapply(last) with nthArg(1) . 再或者,我可以内联larger ,或者用nthArg(0)替换nthArg(0) unapply(head) ,用nthArg(1)替换nthArg(1) unapply(last) nthArg(1)

But none of these options is as readable as the original. 但是这些选项都不比原始选项更具可读性。 Ramda adds nothing here that I can see. Ramda在这里看不到任何内容。 Note that I am a big fan of Ramda; 请注意,我是Ramda的忠实粉丝; I started the library and am one of its principle authors. 我创办了图书馆,是图书馆的主要作者之一。 But I don't think it should be used for every problem. 但我认为不应将其用于所有问题。

The reason why you don't have to wrap everything in thunks (ie functions that take no arguments) in Scheme is because cond is a macro that expands to nested if s, in your case: 之所以不必在Scheme中将所有内容包装在thunk中(即不带参数的函数),是因为cond是一个宏,在您的情况下,扩展为嵌套if

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

So nope, if you want to avoid ternary operators and wrapping everything in thunks you don't have much of a choice with vanilla JS. 因此,不,如果您想避免三元运算符并将所有内容包装在thunk中,那么使用Vanilla JS则没有太多选择。

If you don't mind using non-standard JS, you could implement cond with a macro with Sweet.js ... 如果您不介意使用非标准JS,则可以使用Sweet.js宏实现cond ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM