<b>本文讲的是准备充分了嘛就想学函数式编程?(Part 3),</b>
<b></b>
作为程序员,懒惰是我们的美德。我们不想不断重复地构建,测试,部署写过的代码。
我们希望有办法可以一处写完,各处复用。
代码复用听起来很棒,实现起来很困难。如果代码写的非常明确,就不能复用。太泛化的话,最开始用都困难。
所以我们需要权衡,有种方案是写简短可复用的代码,我们可以将它们当作零件用来组合成更复杂的代码。
在函数式编程中,函数就是我们的零件。我们可以用它们来完成指定的任务,再像乐高积木一样拼凑在一起。
这被称作函数组合。
该怎么实现呢,让我们从两个 JavaScript 函数开始:
好多了,现在设想我们再需要一个函数,它可以接受一个值作为参数,将值加 10,再乘以 5,把结果返回。我们可以写成:
尽管这只是一个很简单的需求,我们仍不想重新写一个新的函数。首先,我们可能会因为忘记括号而出错。
其次,我们已经有一个函数可以将值加上 10,另一个函数将值可以乘以 5。我们这是在重复之前的工作。
因此,我们用 add10 和 mult5 来构建我们的新函数:
我们可以用现有的函数来创建 mult5AfterAdd10 函数,但其实有更好的办法。
在数学中, f ∘ g 是函数的组合,所以读作 “函数 f 与函数 g 的复合函数”,或者更通用的说法是 “在 g 之后调用 f”。所以 (f ∘ g)(x) 相当于先以 x 为自变量调用函数 g,再以结果为自变量调用函数 f,简写成 f(g(x))。
对于我们的例子,我们可以用 mult5 ∘ add10 或者 “mult5 after add10” 来表示,所以我们的函数名叫mult5(add10(value)) 。
在 Elm 中,你可以用插入运算符 << 来组合函数。这在带给我们一种数据是怎样流动的视觉效果。首先,value 传入 add10中,再将结果作为参数传入 mult5 中。
注意 mult5AfterAdd10 中的括号,比如 (mult5 << add10)。这里是说明函数是先组合,再传入参数 value 的。
你可以用这种方式随意组合函数:
这里 x 传入函数 t ,将运算结果传给函数 r,然后再将结果传给函数 s,这样一直进行下去。如果你要在 JavaScript 里实现类似的功能,看起来会是这样 g(h(s(r(t(x))))),括号的恶梦。
有一种可以不需要指定参数的函数写法,叫做 Point-Free 表示法。开始时,这种风格看起来有些奇怪,随着使用继续,你会开始欣赏它带来的简洁性。
你可以注意到,在 mult5AfterAdd10 里我们有两处用到 value 变量。一处是在参数列表中,一处是内部使用时。
其实这个参数并不是必须的,因为 add10,组合中最外侧的函数,和函数组合接受的参数相同。与下面的 point-free 版本是等价的:
用这种 point-free 风格表示法有很多好处。
首先,我们不需要指定多余的参数。因为我们不要明确指定它们,我们可以不用去费心给它们起名字。
其次,因为更简洁,阅读和理解起来也更容易。这个例子非常简单,但是想象一下如果函数有很多参数的情况。
到目前为止,我们已经见过函数组合是怎样工作的,我们如何用 Point-Free 风格的写法来提高代码的简洁性,清晰性和灵活性。
现在让我们尝试在稍微不同的场景中运用这些思想。设想我们用 add 替换 add10:
我们如何只用这两个函数来组合 mult5After10 呢?
继续读之前请先思考这个问题,想一想,试着做一做。
好,如果你真的花时间想了,也许你会想到这样的方案:
但是这不行,为什么?因为 add 函数需要两个参数。
用 Elm 也许不明显,可以用 JavaScript 写:
这段代码是错的,为什么?
因为在这里 add 函数只接受了两个参数中的一个,然后错误结果再被传入 mult5 函数,结果也是错的。
实际上,在 Elm 中,编译器不会让你写出这种残缺的代码( Elm 的优点之一)
这样不是 point-free 的,但可用。但是现在不再是函数组合了,我写了一个新的函数。另外,如果函数更复杂,例如,如果我想用 mult5AfterAdd10 与其他函数组合,那就会很麻烦。
可见函数组合的可用性有限,因为我们不能将这两个函数结合在一起。太糟了。
我们怎样解决这个问题呢?我们需要做什么?
如果我们可以找到一种方法可以让 add 函数先接受一个参数,再在后面调用 mult5AfterAdd10 时接受第二个参数就太棒了。
真的有这样一种方法,叫做 柯里化 。
到目前暂时足够消化一段了。
在文章接下来的部分里,我会涉及到柯里化,函数式编程中常见的函数(如 map,filter,fold 等),参照透明性等。
<b>原文发布时间为:2016年11月17日</b>
<b>本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。</b>