Javascript 如何正确使用Ramda/JS组合函数
作为学习Ramda.js练习的一部分,我正在尝试使用函数方法来解决特定问题 所以我有一个测试:Javascript 如何正确使用Ramda/JS组合函数,javascript,functional-programming,ramda.js,Javascript,Functional Programming,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"));
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时,因为它应该是curry(通过R.find),所以它应该返回一个需要缺少参数的函数。因此,如果我这样做,测试将失败:
let lookupByShortName = R.find(R.propEq("short"));
在这里,lookupByShortName应该成为一个需要一个缺少的参数的函数,所以理论上,我认为我应该能够调用这个函数,如下所示:
lookupByShortName("t")
或者更具体地说(在末尾附加“t”):
。。。但我错了,因为这不起作用,测试失败:
let lookupByShortName = R.find(R.propEq("short"));
1) 将短参数名称映射为长选项名称将短名称映射为长
名称无点:
TypeError:lookupByShortName不是函数
仅限于Context.it(test/validator.spec.js:744:20)
因此,我想到了另一个解决方案(它不起作用,但我不明白为什么):
由于“t”是传递给R.propEq的第二个参数,请使用R.uuuu占位符,然后在末尾传递“t”:
let lookupByShortName = R.find(R.propEq("short"))("t");
let lookupByShortName = R.find(R.propEq("short", R.__))("t");
我已经阅读了一系列关于a的文章,虽然我的理解更好,但我还没有做到
谢谢,你能告诉我哪里出了问题吗。第一个问题是为什么你的代码不起作用 解释这一点的最简单方法是使用函数签名 我们从
propEq
开始:
propEq :: String -> a -> Object -> Boolean
在哈克尔这样的语言中,情况就是这样propEq
是一个函数,它接受字符串并返回一个接受任意类型的函数,返回一个接受对象并返回布尔值的函数。你可以把它写得更明确,比如
propEq :: String -> (a -> (Object -> Boolean))
您可以使用如下语法将其称为:
propEq('short')('t')({ long: "perky", short: "p" }); //=> false
拉姆达有一个稍微不同的想法,即你不必一次通过这些考试。因此,有几种同样有效的方法来调用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
let lookupByShortName = (abbrv, options) => R.find(R.propEq("short", abbrv), options);
lookupByShortName('t', options); //=> {"long": "turky", "short": "t"}
let lookupByShortName = R.useWith(R.find, [R.propEq('short'), R.identity]);
接下来,我们将看到find
,如下所示:
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
let lookupByShortName = (abbrv, options) => R.find(R.propEq("short", abbrv), options);
lookupByShortName('t', options); //=> {"long": "turky", "short": "t"}
let lookupByShortName = R.useWith(R.find, [R.propEq('short'), R.identity]);
出于类似的原因,这意味着在拉姆达:
find :: (a -> Boolean) -> ([a] -> a)
:: ((a -> Boolean), [a]) -> a
当你打电话的时候
find(propEq('short'))
您正试图将a->Object->Boolean
作为第一个参数传递给find
,它希望将a->Boolean
作为第一个参数。虽然Javascript不是强类型的,而且Ramda也没有尝试提供太多强类型的帮助,但是您有一个类型不匹配的问题。事实上,您已经沉没了,尽管Ramda将接受您的函数,就像它可以工作一样,并返回类型为[a]->a
的函数。但是这个函数不能正常工作,因为find
所做的是将[a]
中的每个a
传递到我们的propEq('short')
,直到其中一个返回true
。这永远不会发生,因为propEq('short')
的签名是a->Object->Boolean
,所以当我们传递a
时,我们不会得到Boolean,而是从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
let lookupByShortName = (abbrv, options) => R.find(R.propEq("short", abbrv), options);
lookupByShortName('t', options); //=> {"long": "turky", "short": "t"}
let lookupByShortName = R.useWith(R.find, [R.propEq('short'), R.identity]);
这是干净、清晰的代码。我可能就这样离开了。但是如果你真的希望它是无点数的,Ramda为这种情况提供了最新的解决方案。您可以这样使用它:
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
let lookupByShortName = (abbrv, options) => R.find(R.propEq("short", abbrv), options);
lookupByShortName('t', options); //=> {"long": "turky", "short": "t"}
let lookupByShortName = R.useWith(R.find, [R.propEq('short'), R.identity]);
这可以看作是两个参数的(curried)函数。第一个参数传递给propEq('short')
,返回类型为(a->Boolean)
的新函数,第二个参数传递给identity
,它不进行转换,只完整传递值。然后将这两个结果传递到find
useWith
和类似的功能非常特定于Ramda。如果你不需要点免费版本(例如,作为一个学习练习),这个版本的第一个版本可能是更好的。谢谢史葛的回答,我需要一些时间来考虑和正确地理解它,在我正确地评论之前。为现在干杯。。。