何时进行函数式编程

时间:2018-12-19 13:21:17

标签: javascript functional-programming

我熟悉函数式编程中的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函数的名称是什么。等等。

谢谢

2 个答案:

答案 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强调以下事实:在您的语言您的域中,函数是一等公民(您可以通过传递函数值来为您的域建模)。 / li>
  • 如果在您的应用的关键路径上发生流量,这在JS中会产生巨大的成本。
  • 咖喱函数的参数位置必须一致。例如,按照惯例,转换函数会将要迭代的集合作为最后一个参数。

关于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");
    }
};