我熟悉函数式编程中的currying功能。
用于语言JavaScript。
是的,我知道JS不能完全正常运行,但是它支持currying。
所以我的两个问题是:
1)何时使用咖喱,何时不使用。有什么规定吗?
2)如果我自动执行所有功能,有什么弊端。
例如:
const add = (x, y) => x + y
const curryAdd = autoCurry(add) - imagine autoCurry from some library
那样会有2个相似的功能
但是,如果我启动新项目,并且将所有函数都设为单个参数,则像这样:
const add = x => y => x + y
在任何我调用添加函数的地方都是这样:
add(3)(5)
代替此
add(3, 5)
它只会再增加1个字符。
那么,使所有项目功能都受到不利影响的地方是什么?
这意味着文件系统库,数据库访问等。
否则,我将有许多“几乎重复”的功能-常规功能和咖喱一次。 这增加了复杂性,因为您必须问自己我应该使用curried函数还是常规函数,以及curried函数的名称是什么。等等。
谢谢
答案 0 :(得分:2)
对此有不同的思想流派,一种流派不一定比其他流派更具“功能性”。但首先:
ramda之类的库具有支持两种语法的curry函数:
const add = R.curryN(2, (x, y) => x + y);
add(2)(3); // 5
add(2, 3); // 5
所以不要太想区别。
在使用JavaScript进行精简时,有一个相当重要的惯用语实际上是做不到的:varargs。我的意思是,您可能能够找到一种(繁琐的,令人费解的)方法来使它起作用,但是通常您不会。因此,如果一个函数可以接受任意数量的参数,则不应使用该函数。
接下来要关注的是性能。
与例如相比,有很多额外的函数调用。
const add = (x, y) => x + y;
const add3 = add.bind(null, 3);
在第一个版本中,每次调用add
都要付出代价。有了这个,只有部分应用的版本可以运行,并且它使用内置的(可能更快)启动。
最后,关于合同的一句话:
当您向除您之外的任何人(同事,客户,开放源代码用户)公开功能时,您与他们签订的合同就是这种功能的工作方式。如果您发现以后需要更改它,则有一些更改会打断现有的呼叫者,而那些不会。没有人会在乎后者,每个人都会骂你为后者。
从未咖喱到咖喱(例如通过ramda)是一种不间断的变化。您现有的呼叫者仍然可以使用。相反,不是。
鉴于所有这些,默认情况下,我将可能不咖喱任何函数,除非我非常非常确定每次都将它们称为零碎的。请记住,您的呼叫者(即使您是来自其他模块的呼叫者)也可以始终自己咖喱它!
答案 1 :(得分:2)
Currying是对函数应用自变量序列到对单个自变量应用函数序列的转换。在JS中,这意味着创建了一堆Function
,这在运行时会产生巨大的成本。但是,这在表达能力方面也有好处,例如:
// the mapping function is
// created at each invocation of add2
const add2 = (coll) => map((x) => x + 2, coll);
// the mapping function is
// created once
const add2 = map((x) => x + 2);
这说明了
关于currying和函数式编程还有很多要说的。请注意,currying是通过JS中的功能转换实现的,但是您可以通过其他方式获得一些好处,支持多arar签名是其中之一。在上面的示例中,您可以将map
函数定义为:
const map = (...args) => {
switch (args.length) {
case 1:
return coll => coll.map(args[0]);
case 2:
return args[1].map(args[0]);
default:
throw new Error("Wrong arity, expects one or two arguments");
}
};