如果你想做一个函数编程程序员(第三部分)

如果你想做一个函数编程程序员(第三部分)

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

这是一篇自译的文章(来源于机译和自己的理解),希望对大家有所启发。(如有侵权,请与我联系,侵权必删!!!)
在这里插入图片描述
迈出第一步来理解函数式编程概念是最重要的,有时也是最困难的一步。关于这一点,仁者见仁智者见智。

先前的部分:第1部分第2部分

函数组合
在这里插入图片描述

作为程序员,我们很懒。我们不想一遍又一遍地构建,测试和部署我们编写的代码。
我们一直在努力弄清楚一次完成工作的方式以及如何重用它来做其他事情。
代码重用听起来不错,但很难实现。使代码过于具体,您将无法重用它。使其过于笼统,一开始使用起来可能会太困难。
因此,我们需要在两者之间取得平衡,这是制作更小,可重用的代码的一种方法,我们可以将其用作构建更复杂功能的构建块。
在函数式编程中,函数是我们的基础。我们编写它们来执行非常具体的任务,然后像Lego™积木一样将它们组合在一起。
这称为功能组合。
那么它是怎样工作的?让我们从两个Javascript函数开始:

var add10 = function(value) {
    return value + 10;
};
var mult5 = function(value) {
    return value * 5;
};

这太冗长了,因此让我们使用箭头函数将其重写:

var add10 = value => value + 10;
var mult5 = value => value * 5;

这样更好 现在让我们想象一下,我们还想拥有一个函数,该函数需要一个值并将其加10,然后将结果乘以5。我们可以这样写:

var mult5AfterAdd10 = value => 5 * (value + 10)

即使这是一个非常简单的示例,我们仍然不想从头开始编写此函数。首先,我们可能会犯一个错误,例如忘记括号。
第二,我们已经有一个函数,该函数将10加,再乘以5。让我们用已经编写的代码来编写。
因此,让我们使用add10和mult5来构建我们的新函数:

var mult5AfterAdd10 = value => mult5(add10(value));

我们只是使用现有函数来创建mult5AfterAdd10,但是有一种更好的方法。

在数学上,f∘g是函数组合,被理解为“由g构成的f”,或更常见的是“f after g”。所以 **(f ∘ g)(x)等效于调用f()后调用g(x)**或简单地,f(g(x))

在我们的示例中,我们有mult5∘add10或“ mult5 after add10”,因此我们的函数名为mult5AfterAdd10。
这正是我们所做的。在我们用value或简单地称为mult5(add10(value))调用add10之后,我们调用了mult5。
由于Javascript本身并不执行函数组合,因此让我们来看一下Elm:

add10 value =
    value + 10
mult5 value =
    value * 5
mult5AfterAdd10 value =
    (mult5 << add10) value

<<运算符是如何在Elm中组合函数的。它使我们对数据的流动方式有了直观的了解。首先,将值传递给add10,然后将其结果传递给mult5。
注意在mult5AfterAdd10中的括号,即(mult5 << add10)。他们在那里确保在应用值之前首先组成函数。
您可以通过这种方式组合任意数量的函数:

f x =
   (g << h << s << r << t) x

在这里,x传递给函数t,函数的结果传递给r,函数的结果传递给s,依此类推。如果您在Javascript中做了类似的事情,它将看起来像g(h(s(r(t(x(x)))))),这是一场噩梦

Point-Free Notation
在这里插入图片描述

有一种编写函数的样式,而不必指定参数称为Point-Free Notation。一开始,这种风格看起来很奇怪,但是随着您的继续,您会逐渐体会到简洁。
在mult5AfterAdd10中,您会注意到该值被指定了两次。一次在参数列表中,一次在使用时。

-- 该函数需要1个参数
mult5AfterAdd10 value =
    (mult5 << add10) value

但是此参数不是必需的,因为组合中最右边的函数add10期望使用相同的参数。以下point-free version是等效的:

-- 这也是一个需要1个参数的函数
mult5AfterAdd10 =
    (mult5 << add10)

使用point-free版本有很多好处。
首先,我们不必指定冗余参数。并且由于我们不必指定它们,所以我们不必为所有的它们想出名字。
其次,由于它不那么冗长,因此更易于阅读和推理。这个例子很简单,但是想像一下一个带有更多参数的函数。

Trouble in Paradise
在这里插入图片描述

到目前为止,我们已经了解了函数组合的工作原理以及为简洁,清晰和灵活起见,应如何应用Point-Free Notation。
现在,让我们尝试在稍有不同的情况下使用这些想法,然后看看它们的效果如何。假设我们将add10替换为add:

add x y =
    x + y
mult5 value =
    value * 5

我们如何仅使用这两个函数编写mult5After10?
在继续阅读之前,请先考虑一下。去认真想一想。尝试做一做。
好的,因此,如果您确实花时间考虑这一点,则可能想出了一个解决方案,例如:

-- This is wrong !!!!
mult5AfterAdd10 =
    (mult5 << add) 10 

但这是行不通的。为什么?因为add需要2个参数。
如果这在Elm中不明显,请尝试使用Javascript编写:

var mult5AfterAdd10 = mult5(add(10)); // this doesn't work

这段代码是错误的,但是为什么呢?
由于add函数在这里仅获得其2个参数中的1个,因此其不正确的结果将传递给mult5。这将产生错误的结果。
实际上,在Elm中,编译器甚至不允许您编写格式错误的代码(这是Elm的一大优点)。
让我们再试一次:

var mult5AfterAdd10 = y => mult5(add(10, y)); // not point-free

这不是point-free,但我可能可以接受。但是现在我不再只是结合功能了。我正在写一个新函数。另外,如果这变得更加复杂,例如,如果我想将mult5AfterAdd10与其他内容组合在一起,那么我将陷入真正的麻烦。
因此,由于我们不能将这两个功能结合使用,因此功能组合的用途似乎很有限。太糟糕了,因为它是如此强大。
我们该如何解决呢?要解决这个问题,我们需要什么?
那么,什么是伟大的解决办法,如果我们有给予我们某种方式添加的唯一功能的参数之一的时间提前,然后它会得到它的第二个参数后,当mult5AfterAdd10被调用。
原来有办法,叫做Currying。
我的脑子!!!!

现在足够了。
在本文的后续部分中,我将讨论Currying,常用功能(例如,地图,过滤器,折叠等),参照透明性等。
接下来:第4部分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值