库里在圣斗士和拉姆达之间有什么不同



当我使用Sanctuary而不是Ramda时,我被"Professor's Frisby…"中的咖喱示例卡住了。我得到了一个错误:"‘curry2’最多需要三个参数,但收到了五个参数。"而Ramda工作得很好。我确信我做错了什么,但我想不通。

以本书为例:

var match = curry2((what, str) => {return str.match(what);});
var hasSpaces = match(/s+/g);
var filter = curry2((f, ary) => {return ary.filter(f);});
var f2 = filter(hasSpaces, ["tori_spelling", "tori amos"]);

我得到

TypeError: Function applied to too many arguments
curry2 :: ((a, b) -> c) -> a -> b -> c
‘curry2’ expected at most three arguments but received five arguments.

庇护所比Ramda严格得多。它确保函数只应用于正确数量的参数,并且参数具有预期的类型。例如,S.add(42, true)是一个类型错误,而R.add(42, true)的计算结果为43

在您的案例中,问题是Array#filter将给定的函数应用于三个参数(elementindexarray)。然而,hasSpaces只需要一个参数。

解决方案是使用S.filter而不是Array#filter:

const match = S.curry2((what, str) => str.match(what));
const hasSpaces = match(/s+/g);
const f2 = S.filter(hasSpaces, ['tori_spelling', 'tori amos']);

做出这一改变后,另一种类型的错误被揭示出来:

TypeError: Invalid value
filter :: (Applicative f, Foldable f, Monoid f) => (a -> Boolean) -> f a -> f a
^^^^^^^
1
1)  null :: Null
The value at position 1 is not a member of ‘Boolean’.
See https://github.com/sanctuary-js/sanctuary-def/tree/v0.12.1#Boolean for information about the Boolean type.

S.filter期望谓词作为其第一个参数。严格来说,谓词是一个返回truefalse的函数。然而,String#match返回null或匹配数组。

解决方案是使用S.test而不是String#match:

const hasSpaces = S.test(/s+/);
const f2 = S.filter(hasSpaces, ['tori_spelling', 'tori amos']);

在这一点上,hasSpaces的定义非常明确,给它起个名字没有多大价值。我们可以将代码写成一个单独的表达式:

S.filter(S.test(/s/), ['tori_spelling', 'tori amos'])

注意,图案可以从/s+/g简化为/s/。当使用S.test时,g标志没有作用,并且+不是必需的,因为我们对带空格的字符串感兴趣,但对计算空格不感兴趣。

最新更新