第862期成为一名函数式码农之三

Posted 前端早读课

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第862期成为一名函数式码农之三相关的知识,希望对你有一定的参考价值。

前言

3月2号早读文章继续连载《成为一名函数式码农系列》,本文由@唐先僧翻译授权分享。


正文从这开始~

作为码农,我们都很懒。我们不想一遍又一遍的编译、测试、部署我们已经写过的代码。


我们总是尝试找到一种方法可以只编写一次代码然后怎么复用它来做别的事情。


代码复用听起来很好但是很难实现。代码太具体就无法复用。太通用第一次很难使用。


所有我们需要在这两者间做一个平衡,寻求创建一些更小、可复用的代码片段的方式,这些代码片段可以作为构建更复杂功能的砖块。


在函数式编程中,函数就是我们的砖块。我们编写一些可以完成非常具体任务的函数,然后像乐高积木一样将他们搭建起来。


这就是所谓的函数组合。


那么它是怎么工作的?我们以两个javascript函数开头:

【第862期】成为一名函数式码农之三


这太啰嗦了,让我们用箭头函数(fat arrow)表示法重写:

【第862期】成为一名函数式码农之三


这样好一些。现在想象一下,我们需要一个函数接收一个参数,将该参数加10然后乘以5。我们可以这样写:

【第862期】成为一名函数式码农之三


尽管这是一很简单的例子,我们也不想从0开始编写这个函数。首先我们可能会出错,比如忘记括弧。


其次我们已经有一个函数可以加10,以及另外一个函数可以乘以5。我们在重复我们已经写过的代码。


所以取而代之,让我们使用add10和mult5来创建新函数:

【第862期】成为一名函数式码农之三


我们仅仅使用现有的函数来创建mult5AfterAdd10,但是还有更好的方式。


在数学中,f ∘ g是复合函数,读作“f composed with g”,或者更常用的,“f after g”。 所以(f ∘ g)(x)等同于给定参数x调用g之后调用f,或者简单的说f(g(x))。


在我们的例子中,有mult5 ∘ add10或者说“mult5 after add10”,所以函数的名称是mult5AfterAdd10。


这个函数名也准确的说明了我们做的事情。我们先调用了 add10 然后调用 mult5,参数是value。 或者:mult5(add10(value))。


由于JavaScript本身不支持组合函数,我们来看Elm中的实现:

【第862期】成为一名函数式码农之三


<<插入运算符是Elm语言中组合函数的方式。它直观得告诉我们数据的流向。首先,value传递给add10, 然后结果被传递给mult5。


注意 mult5AfterAdd10中的括弧,即(mult5 << add10),它们确保在接收参数value之前先组合函数。


你也可以像这样按照你的需要组合任意多的函数:

【第862期】成为一名函数式码农之三


这里 x被传递给函数t,其结果被传递给r,结果再传递个s。。。如果用JavaScript实现应该是这个样子g(h(s(r(t(x))))),括号的噩梦。


Point-Free Notation

【第862期】成为一名函数式码农之三


Point-Free Notation就是在编写函数时不需要指定参数的编程风格。一开始,这风格看起来有点奇怪,但是随着不断深入,你会逐渐喜欢这种简洁的方式。


在multi5AfterAdd10中,你会注意到value被指定了两次。一次在参数列表,另一次是在它被使用时。

【第862期】成为一名函数式码农之三


但是这个参数不是必须的,因为该函数组合的最右边一个函数也就是add10期望相同的参数。下面的 point-free 版本是等效的:

【第862期】成为一名函数式码农之三


使用 point-free 版本有很多好处。


首先,我们不需要指定冗余的参数。由于不必指定参数,所以也就不必考虑为它们命名。


其次,由于更简短使得更容易阅读。本例比较简单,想象一下如果一个函数有多个参数的情况。


乐园的麻烦

【第862期】成为一名函数式码农之三


到目前为止,我们已经了解了函数组合如何工作以及如何通过point-free风格使函数简洁、清晰、灵活。


现在,我们尝试将这些知识应用到一个稍微不同的场景。想象一下我使用add来替换add10:

【第862期】成为一名函数式码农之三


在只有这两个函数的情况下我们怎么实现mult5After10?


继续阅读之前思考一下。不用很严肃,考虑一下。尝试实现它。


好的,如果你真的花时间思考了,你也许会给出类似这样的解决方法:

【第862期】成为一名函数式码农之三


但是这个无法运行。为什么?因为add需要两个参数。


如果在Elm语言中这还不明显的话,尝试将这一段代码用JavaScript实现:

【第862期】成为一名函数式码农之三


这段代码是错误的,但是为什么?


因为这里add函数只能获取到两个参数(它的函数定义中指定了两个参数)中的一个(实际只传递了一个参数),所以它会将一个错误的结果传递给mult5。这最终会产生一个错误的结果。


事实上,在Elm中,编译器不允许你写出这种格式错误的代码(这是Elm的妙处之一)。


我们再试一次:


这个不是point-free风格但是我觉得还行。但是现在我不再仅仅组合函数。我在写一个新函数。同样如果这个函数更复杂,例如,我想使用一些其他的东西来组合mult5AfterAdd10,我真的会遇到麻烦。


所以由于我们不能将这个两个函数对接将会出现函数组合的作用受限。这太糟糕了因为函数组合是如此强大。


我们怎么解决这个问题?我们需要什么来消除这个问题?


然而,如果我们用某种方法提前仅给add函数一个参数,稍后在mult5After10被调用时它(add)能获取到第二个参数,这才是真正妙的地方。


事实证明有一种方法,它就是柯里化(Currying)。


最后,你可能还需要:




关于本文

译者:@唐先僧

译文:http://www.jianshu.com/p/5e851a0f45fc

原文:https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7#.9bzrt9rf6

以上是关于第862期成为一名函数式码农之三的主要内容,如果未能解决你的问题,请参考以下文章

第883期成为一名函数式码农系列之五

第858期成为一名函数式码农之一

第888期成为一名函数式码农系列之六

第882期成为一名函数式码农系列之四

it码农之心灵鸡汤

第36期函数式编程和响应式编程资料汇总