04. So You Want to be a Functional Programmer (Part 4)

相关链接:

https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-4-18fbe3ea9e49

Taking that first step to understanding Functional Programming concepts is the most important and sometimes the most difficult step. But it doesn’t have to be. Not with the right perspective.

  • 采用第一步来理解功能编程概念是最重要的,有时也是最困难的步骤。 但它不一定是。 没有正确的观点。

If you remember from Part 3, the reason that we were having problems composing mult5 and add (in ) is because mult5 takes 1 parameter and addtakes 2.

  • 如果你记得第3部分,我们在编写mult5和add(in)时遇到问题的原因是因为mult5方法需要1个参数,add方法需要2个。

We can solve this easily by just restricting all functions to take only 1 parameter.

  • 我们可以通过将所有函数限制为仅采用1个参数来轻松解决此问题。

Trust me. It’s not as bad as it sounds.

  • 相信我。 它没有听起来那么糟糕。

We simply write an add function that uses 2 parameters but only takes 1 parameter at a time. Curried functions allow us to do this.

  • 我们只需编写一个使用2个参数的add函数,但一次只需要1个参数。 *** Curried ***功能允许我们这样做。

A Curried Function is a function that only takes a single parameter at a time.

  • Curried Function是一个一次只接受一个参数的函数。

This will let us give add its first parameter before we compose it with mult5. Then when mult5AfterAdd10 is called, add will get its second parameter.

  • 这将让我们在用mult5编写它之前给add方法传递它的第一个参数。 然后当调用mult5AfterAdd10时,add将获得其第二个参数。

In Javascript, we can accomplish this by rewriting add:

  • 在Javascript中,我们可以通过重写add来实现这一点:

var add = x => y => x + y

This version of add is a function that takes one parameter now and then another one later.

  • 这个版本的add是一个函数,它现在接受一个参数,然后再接受另一个参数。

In detail, the add function takes a single parameter, x, and returns a function that takes a single parameter, y, which will ultimately return the result of adding x and y.

  • 详细地说,add函数接收一个参数x,并返回一个接收一个参数y的函数,该参数将最终返回添加x和y的结果。

Now we can use this version of add to build a working version of mult5AfterAdd10:

  • 现在我们可以使用这个版本的add来构建mult5AfterAdd10的工作版本:

var compose = (f, g) => x => f(g(x));
var mult5AfterAdd10 = compose(mult5, add(10));

The compose function takes 2 parameters, f and g. Then it returns a function that takes 1 parameter, x, which when called will apply f after g to x.

  • compose函数有两个参数f和g。 然后它返回一个接收参数x的函数,该函数在被调用时将x传递给g方法,之后从g方法返回的结果传递给f方法。

So what did we do exactly? Well, we converted our plain old add function into a curried version. This made add more flexible since the first parameter, 10, can be passed to it up front and the final parameter will be passed when mult5AfterAdd10 is called.

  • 那我们到底做了什么? 好吧,我们将普通的add方法转换为curried version.。 这使得add 方法更加灵活,因为第一个参数10可以预先传递给它,最后一个参数将在调用mult5AfterAdd10时传递。

At this point, you may be wondering how to rewrite the add function in Elm. Turns out, you don’t have to. In Elm and other Functional Languages, all functions are curried automatically.

  • 此时,您可能想知道如何在Elm中重写add函数。 事实证明,你不必这么做。 在Elm和其他功能语言中,所有功能都会自动进行。(所有功能都自动调整)

So the add function looks the same:

  • 所以add函数看起来是一样的:
image.png

This is how mult5AfterAdd10 should have been written back in Part 3:

  • 这就是mult5AfterAdd10应该在第3部分中写回的方式:
image.png

Syntactically speaking, Elm beats Imperative Languages like Javascript because it’s been optimized for Functional things like currying and composition.

  • 从语法上讲,Elm击败了像Javascript这样的命令式语言,因为它已经针对像currying和composition这样的功能性事物进行了优化。
image.png

Another time currying shines is during refactoring when you create a generalized version of a function with lots of parameters and then use it to create specialized versions with fewer parameters.

  • 另一个时间是在重构期间,当您创建具有大量参数的函数的通用版本时,然后使用它来创建具有较少参数的专用版本。

For example, when we have the following functions that put brackets and double brackets around strings:

  • 例如,当我们有以下函数将括号和双括号放在字符串周围时:
image.png

Here’s how we’d use it:

  • 以下是我们如何使用它:
image.png

We can generalize bracket and doubleBracket:

  • 我们可以概括括号和doubleBracket:
image.png

But now every time we use generalBracket we have to pass in the brackets:

  • 但是现在每次我们使用generalBracket时我们都要传递括号:
image.png

What we really want is the best of both worlds.

  • 我们真正想要的是两全其美。

If we reorder the parameters of generalBracket, we can create bracket and doubleBracket by leveraging the fact that functions are curried:

  • 如果我们重新排序generalBracket的参数,我们可以通过利用函数curried的事实来创建括号和doubleBracket:
image.png

Notice that by putting the parameters that were most likely to be static first, i.e. prefix and suffix, and putting the parameters that were most likely to change last, i.e. str, we can easily create specialized versions of generalBracket.

  • 请注意,通过首先放置最可能是静态的参数,即前缀和后缀,并放置最有可能最后改变的参数,即str,我们可以轻松地创建generalBracket的专用版本。

Parameter order is important to fully leverage currying.
Also, notice that bracket and doubleBracket are written in point-free notation, i.e. the str parameter is implied. Both bracket and doubleBracket are functions waiting for their final parameter.

  • 参数顺序对于充分利用currying非常重要。
    另请注意,括号和doubleBracket是以无点表示法编写的,即str参数是隐含的。 括号和doubleBracket都是等待其最终参数的函数。

Now we can use it just like before:

  • 现在我们可以像以前一样使用它:
image.png

But this time we’re using a generalized curried function, generalBracket.

  • 但这一次我们使用的是广义curried函数generalBracket。

Common Functional Functions

  • 常用功能
image.png

Let’s look at 3 common functions that are used in Functional Languages.

  • 我们来看一下Functional Languages中使用的3个常用函数。

But first, let’s look at the following Javascript code:

  • 但首先,让我们看看以下Javascript代码:
image.png

There’s one major thing wrong with this code. It’s not a bug. The problem is that this code is boilerplate code, i.e. code that is written over and over again.

  • 这段代码有一个重大问题。 这不是一个错误。 问题是这段代码是样板代码,即一遍又一遍地写的代码。

If you code in Imperative Languages like Java, C#, Javascript, PHP, Python, etc., you’ll find yourself writing this boilerplate code more than any other.

  • 如果您使用诸如Java,C#,Javascript,PHP,Python等命令式语言进行编码,您将发现自己编写的样板代码比其他任何代码都要多。

That’s what’s wrong with it.

  • 这就是它的错误。

So let’s kill it. Let’s put it in a function (or a couple of functions) and never write a for-loop again. Well, almost never; at least until we move to a Functional Language.

  • 所以,让我们杀了它。 让我们把它放在一个函数(或几个函数)中,永远不要再写一个for循环。 好吧,几乎没有; 至少在我们转向功能语言之前。

Let’s start with modifying an array called things:

  • 让我们从修改一个名为thing的数组开始:
image.png

UGH!! Mutability!

  • 啊!!可变性!

Let’s try that again. This time we won’t mutate things:

  • 让我们再试一次。 这次我们不会改变事情:
image.png

Okay, so we didn’t mutate things but technically we mutated newThings. For now, we’re going to overlook this. We are in Javascript after all. Once we move to a Functional Language, we won’t be able to mutate.

  • 好吧,所以我们没有改变事物,但从技术上讲,我们改变了新事物。 现在,我们将忽略这一点。 毕竟我们在Javascript中。 一旦我们转向函数式语言,我们将无法改变。

The point here is to understand how these functions work and help us to reduce noise in our code.

  • 这里的要点是了解这些功能如何工作并帮助我们减少代码中的噪音。

Let’s take this code and put it in a function. We’re going to call our first common function map since it maps each value in the old array to new values in the new array:

  • 让我们把这段代码放在一个函数中。 我们将调用我们的第一个公共函数映射,因为它将旧数组中的每个值映射到新数组中的新值:
image.png

Notice the function, f, is passed in so that our map function can do anything we want to each item of the array.

  • 请注意,函数f被传入,以便我们的map函数可以对数组的每个项执行任何操作。

Now we can call rewrite our previous code to use map:

  • 现在我们可以调用重写前面的代码来使用map:
image.png

Look ma. No for-loops. And much easier to read and therefore reason about.

  • 看马。 没有for循环。 而且更容易阅读,因此推理。

Well, technically, there are for-loops in the map function. But at least we don’t have to write that boilerplate code anymore.

  • 嗯,从技术上讲,map函数中有for循环。 但至少我们不必再写那个样板代码了。

Now let’s write another common function to filter things from an array:

  • 现在让我们编写另一个常用函数来过滤数组中的东西:
image.png

Notice how the predicate function, pred, returns TRUE if we keep the item or FALSE if we toss it.

  • 注意如果我们保留项目,谓词函数pred如何返回TRUE,如果我们丢弃它,则返回FALSE。

Here’s how to use filter to filter odd numbers:

  • 以下是使用过滤器过滤奇数的方法:
image.png

Using our new filter function is so much simpler than hand-coding it with a for-loop.

  • 使用我们的新过滤器功能比使用for循环手动编码要简单得多。

The final common function is called reduce. Typically, it’s used to take a list and reduce it to a single value but it can actually do so much more.

  • 最后的常用函数叫做reduce。 通常,它用于获取列表并将其减少为单个值,但它实际上可以做得更多。

This function is usually called fold in Functional Languages.

  • 此功能通常在功能语言中称为折叠。
image.png

The reduce function takes a reduction function, f, an initial start value and an array.

  • reduce函数采用缩减函数f,初始起始值和数组。

Notice that the reduction function, f, takes 2 parameters, the current item of the array, and the accumulator, acc. It will use these parameters to produce a new accumulator each iteration. The accumulator from the final iteration is returned.

  • 请注意,缩减函数f需要2个参数,即数组的当前项和累加器acc。 它将使用这些参数在每次迭代时生成一个新的累加器。 返回最后一次迭代的累加器。

An example will help us understand how it works:

  • 一个例子将帮助我们理解它是如何工作的:
image.png

Notice that the add function takes 2 parameters and adds them. Our reduce function expects a function that takes 2 parameters so they work well together.

  • 请注意,add函数接受2个参数并添加它们。 我们的reduce函数需要一个带有2个参数的函数,以便它们能很好地协同工作

We start with a start value of zero and pass in our array, values, to be summed. Inside the reduce function, the sum is accumulated as it iterates over values. The final accumulated value is returned as sumOfValues.

  • 我们从一个零的起始值开始,并传入我们的数组值,进行求和。 在reduce函数内部,总和在迭代值时累积。 最终累计值以sumOfValues的形式返回。

Each of these functions, map, filter and reduce let us do common manipulation operations on arrays without having to write boilerplate for-loops.

  • 这些函数中的每一个,map,filter和reduce都让我们在数组上进行常见的操作操作,而无需编写样板for循环。

But in Functional Languages, they are even more useful since there are no loop constructs just recursion. Iteration functions aren’t just extremely helpful. They’re necessary.

  • 但是在Functional Languages中,它们甚至更有用,因为没有循环结构只是递归。 迭代函数不仅非常有用。 他们是必要的。

Enough for now.

  • 够了。

In subsequent parts of this article, I’ll talk about Referential Integrity, Execution Order, Types, and more.

  • 在本文的后续部分中,我将讨论参考完整性,执行顺序,类型等。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,332评论 0 10
  • 此文系#茅山娱乐#原创,未经授权,禁止任何形式的转载,但欢迎分享至朋友圈。 昨日(6月18日)晚上7点零5分,演员...
    茅山娱乐阅读 201评论 0 0
  • 人生若只如初见 不会如此诸多念 一念当时花正艳 二念当时梦阑珊 三念当时卿顾盼 四念当时我心乱 时光匆匆谁可管 流...
    倾城_ab99阅读 122评论 0 0
  • 故事 发生在二十三年前 一个来自爱情的摩擦 一个来自生命的碰撞 一个在南方 一个在北方 相隔了几千公里 这本就两个...
    董言阅读 416评论 7 13
  • 习惯,真是一个可怕的东西。 这是我第三次修改手机的字体,新换上的字体是行书,少了些的规整,多了点洒脱,看起来说赏心...
    王斤斤呀阅读 363评论 0 0