编程语言
首页 > 编程语言> > javascript-如何正确使用Ramda / JS编写函数

javascript-如何正确使用Ramda / JS编写函数

作者:互联网

在学习Ramda.js的练习中,我尝试使用一种功能性方法来解决特定问题.

所以我有这个测试:

it.only("map short name to long name POINTFREE", () => {
  let options = [ { long: "perky", short: "p" }, { long: "turky", short: "t" } ];

  let lookupByShortName = R.find(R.propEq("short", "t"));
  let result = lookupByShortName(options);
  expect(result).to.have.property("long", "turky");
});

“选项”用作查找序列.我需要将一系列指定为单个字符的字符串转换为更长的名称,方法是参考选项序列.因此,如选项中所定义,字符“ t”应转换为“ turky”.

但是,这并不是我需要的有用的结构.函数’lookupByShortName’不是通用的,它使用值“ t”进行硬编码.我想要的是省略“ t”参数,以便当您调用lookupByShortName时,因为应该对其进行咖喱处理(由R.find进行处理),因此它应该返回需要缺少参数的函数.因此,如果我这样做,测试将失败:

let lookupByShortName = R.find(R.propEq("short"));

所以在这里,lookupByShortName应该成为需要单个缺少参数的函数,因此从理论上讲,我认为我应该能够按以下方式调用此函数:

lookupByShortName("t")

或更具体地(在末尾附加“ t”):

let lookupByShortName = R.find(R.propEq("short"))("t");

…但是我弄错了,因为这不起作用,测试失败:

1) Map short arg name to long option name map short name to long
name POINTFREE:
TypeError: lookupByShortName is not a function
at Context.it.only (test/validator.spec.js:744:20)

因此,我想到了另一个解决方案(该方法不起作用,但我不明白为什么):

由于“ t”是传递给R.propEq的第二个参数,因此请使用R .__占位符,然后在末尾传递“ t”:

let lookupByShortName = R.find(R.propEq("short", R.__))("t");

我已经完成了有关blog的一系列文章,尽管我的理解更好,但我仍然没有.

谢谢,您能告诉我我要去哪里了吗?

解决方法:

第一个问题是为什么您的代码不起作用.

解释此问题的最简单方法是使用函数签名.

我们从propEq开始:

propEq :: String -> a -> Object -> Boolean

这就是像Hakell这样的语言的样子. propEq是一个函数,它接受一个String并返回一个函数,该函数接受一个任意类型的东西,并返回一个函数,该函数接受一个Object并返回一个布尔值.您可以像这样更明确地编写它

propEq :: String -> (a -> (Object -> Boolean))

您可以使用类似以下的语法来调用它:

propEq('short')('t')({ long: "perky", short: "p" }); //=> false

Ramda的想法略有不同,即您不必一次通过这些.因此,有几种同样有效的方法可以调用Ramda函数:

propEq :: String -> (a -> (Object -> Boolean))
          String -> ((a, Object) -> Boolean)
          (String, a) -> (Object -> Boolean)
          (String, a, Object) -> Boolean

这分别意味着要这样调用它:

propEq('short')('t')({ long: "perky", short: "p" }); //=> false
propEq('short')('t', { long: "perky", short: "p" }); //=> false
propEq('short', 't')({ long: "perky", short: "p" }); //=> false
propEq('short', 't', { long: "perky", short: "p" }); //=> false

接下来我们找到,看起来像这样:

find :: (a -> Boolean) -> [a] -> a 

出于类似的原因,这意味着在Ramda中的原因之一:

find :: (a -> Boolean) -> ([a] -> a)
     :: ((a -> Boolean), [a]) -> a

你打电话时

find(propEq('short'))

您正在尝试通过->对象->布尔作为要查找的第一个参数,它希望将->作为第一个参数.布尔值.尽管Javascript不是强类型化的,并且Ramda不会在强类型化方面提供很多帮助,但是您的类型不匹配.实际上,您已经沉没了,尽管Ramda会像接受功能一样接受您的函数,并返回[a]->类型的函数.一种.但是此函数无法正常工作,因为find所做的是将[a]中的每个a传递到我们的propEq(‘short’)中,直到其中一个返回true为止.这永远不会发生,因为propEq(‘short’)的签名是->.对象->布尔值,因此当我们传递a时,我们不会得到布尔值,而是从Object到Boolean的函数.

这种类型的不匹配是您当前的方法不起作用的原因.

第二个问题是如何使其工作.

最简单的方法是使用如下所示的内容:

let lookupByShortName = (abbrv, options) => R.find(R.propEq("short", abbrv), options);
lookupByShortName('t', options); //=> {"long": "turky", "short": "t"}

这是干净,清晰的代码.我可能会这样离开.但是,如果您真的希望它没有意义,Ramda可以为这种情况提供useWith.您可以像这样使用它:

let lookupByShortName = R.useWith(R.find, [R.propEq('short'), R.identity]);

可以将其视为两个参数的(已固化)函数.第一个参数传递给propEq(‘short’),返回类型为(a-> Boolean)的新函数,第二个参数传递给identity,它不进行任何转换,只传递完整的值.然后将这两个结果传递给find

useWith和类似的converge非常特定于Ramda.如果您不需要无限制版本(例如,作为学习练习),则最好使用第一个版本.

标签:ramda-js,javascript,functional-programming
来源: https://codeday.me/bug/20191111/2019325.html