02. So You Want to be a Functional Programmer (Part 2)

相关链接:
https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-2-7005682cec4a

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.

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

Friendly Reminder

  • 温馨的提示
image.png

Please read through the code slowly. Make sure you understand it before moving on. Each section builds on top of the previous section.

  • 请慢慢阅读代码。 在继续之前确保你理解它。 每个部分都建立在上一节的基础之上。

If you rush, you may miss some nuance that will be important later.

  • 如果你匆忙,你可能会错过一些后来很重要的细微差别。

Refactoring

  • 重构
image.png

Let’s think about refactoring for a minute. Here’s some Javascript code:

  • 让我们考虑重构一分钟。 这是一些Javascript代码:
image.png

We’ve all written code like this before and over time, we start to recognize that these two functions are practically the same and only differ by a few things (shown in bold).

  • 我们之前和之后都编写了这样的代码,我们开始认识到这两个函数实际上是相同的,只是有几点不同(以粗体显示)。

Instead of copying validateSsn and pasting and editing to create validatePhone, we should create a single function and parameterize the things that we edited after pasting.

  • 我们应该创建一个函数并参数化我们在粘贴后编辑的内容,而不是复制validateSsn以及粘贴和编辑以创建validatePhone。

In this example, we would parameterize the value, the regular expression and the message printed (at least the last part of the message printed).

  • 在这个例子中,我们将参数化值,正则表达式和打印的消息(至少打印的消息的最后部分)。

The refactored code:
重构的代码:

image.png

The parameters ssn and phone in the old code are now represented by value.

  • 旧代码中的参数ssn和phone现在由值表示。

The regular expressions /^\d{3}-\d{2}-\d{4}$/ and /^\(\d{3}\)\d{3}-\d{4}$/ are represented by regex.
正则表达式/ ^ \ d {3} - \ d {2} - \ d {4} $ // ^ \(\ d {3} \)\ d {3} - \ d {4} $ /由正则表达式表示。

And finally, the last part of the message ‘SSN’ and ‘Phone Number’ are represented by type.

  • 最后,消息“SSN”和“电话号码”的最后一部分由类型表示。

Having one function is much better than having two functions. Or worse three, four or ten functions. This keeps your code clean and maintainable.

  • 拥有一个功能比拥有两个功能要好得多。 或者更糟糕的是三,四或十个功能。 这可以使您的代码保持清洁和可维护。

For example, if there’s a bug, you only have to fix it in one place versus searching through your whole codebase to find where this function MAY have been pasted and modified.

  • 例如,如果存在错误,您只需将其修复到一个位置,而不是搜索整个代码库以找到粘贴和修改此函数的位置。

But what happens when you have the following situation:

  • 但是当你遇到以下情况时会发生什么:
image.png

Here parseAddress and parseFullName are functions that take a string and return true if it parses.

  • 这里parseAddress和parseFullName是接受字符串的函数,如果它解析则返回true。

How do we refactor this?

  • 我们如何重构这个?

Well, we can use value for address and name, and type for ‘Address’ and ‘Name’ like we did before but there’s a function where our regular expression used to be.

  • 好吧,我们可以使用地址和名称的值,并像之前一样输入“地址”和“名称”但是我们的正则表达式曾经是一个函数。

If only we could pass a function as a parameter…

  • 如果我们只能将函数作为参数传递......

Higher-Order Functions

  • 高阶函数
image.png

Many languages do not support passing functions as parameters. Some do but they don’t make it easy.

  • 许多语言不支持将函数作为参数传递。 有些人会这样做,但他们并不容易。

In Functional Programming, a function is a first-class citizen of the language. In other words, a function is just another value.
Since functions are just values, we can pass them as parameters.

  • 在函数式编程中,函数是该语言的一等公民。 换句话说,函数只是另一个值。
    由于函数只是值,我们可以将它们作为参数传递。

Even though Javascript is not a Pure Functional language, you can do some functional operations with it. So here’s the last two functions refactored into a single function by passing the parsing function as a parameter called parseFunc:

  • 即使Javascript不是纯函数语言,您也可以使用它进行一些功能操作。 所以这里将最后两个函数重构为单个函数,方法是将解析函数作为一个名为parseFunc的参数传递:
image.png

Our new function is called a Higher-order Function.

  • 我们的新函数称为高阶函数。

Higher-order Functions either take functions as parameters, return functions or both.

  • 高阶函数或者将函数作为参数,返回函数或者两者兼而有之。

Now we can call our higher-order function for the four previous functions (this works in Javascript because Regex.exec returns a truthy value when a match is found):

  • 现在我们可以为前面的四个函数调用我们的高阶函数(这在Javascript中有效,因为Regex.exec在找到匹配时返回一个truthy值):
image.png

This is so much better than having four nearly identical functions.

  • 这比具有四个几乎相同的功能要好得多。

But notice the regular expressions. They’re a bit verbose. Let’s clean up our a code by factoring them out:

  • 但请注意正则表达式。 他们有点冗长。 让我们通过将它们分解来清理我们的代码:
image.png

That’s better. Now when we want to parse a phone number, we don’t have to copy and paste the regular expression.

  • 那更好。 现在,当我们想要解析电话号码时,我们不必复制和粘贴正则表达式。

But imagine we have more regular expressions to parse, not just parseSsn and parsePhone. Each time we create a regular expression parser, we have to remember to add the .exec to the end. And trust me, this is easy to forget.

  • 但是想象一下我们有更多的正则表达式来解析,而不仅仅是parseSsn和parsePhone。 每次我们创建一个正则表达式解析器时,我们都必须记住将.exec添加到结尾。 相信我,这很容易忘记。

We can guard against this by creating a high-order function that returns the exec function:

  • 我们可以通过创建一个返回exec函数的高阶函数来防止这种情况:
image.png

Here, makeRegexParser takes a regular expression and returns the exec function, which takes a string. validateValueWithFunc will pass the string, value, to the parse function, i.e. exec.

  • 这里,makeRegexParser采用正则表达式并返回exec函数,该函数接受一个字符串。 validateValueWithFunc将字符串value传递给parse函数,即exec。

parseSsn and parsePhone are effectively the same as before, the regular expression’s exec function.

  • parseSsn和parsePhone实际上和以前一样,是正则表达式的exec函数。

Granted, this is a marginal improvement but is shown here to give an example of a high-order function that returns a function.

  • 当然,这是一个微小的改进,但这里显示的是一个返回函数的高阶函数的例子。

However, you can imagine the benefits of making this change if makeRegexParser was much more complex.

  • 但是,如果makeRegexParser更复杂,您可以想象进行此更改的好处。

Here’s another example of a higher-order function that returns a function:

  • 这是返回函数的高阶函数的另一个例子:
image.png

Here we have makeAdder that takes constantValue and returns adder, a function that will add that constant to any value it gets passed.

  • 这里我们有makeAdder,它接受constantValue并返回adder,这个函数将该常量添加到它传递的任何值。

Here’s how it can be used:

  • 以下是它的使用方法:

We create a function, add10, by passing the constant 10 to makeAdder which returns a function that will add 10 to everything.

  • 我们通过将常量10传递给makeAdder来创建一个函数add10,该函数返回一个函数,该函数将向所有内容添加10。

Notice that the function adder has access to constantValue even after makeAddr returns. That’s because constantValue was in its scope when adder was created.

  • 请注意,即使在makeAddr返回后,函数加法器也可以访问constantValue。 那是因为当创建加法器时,constantValue在其范围内。

This behavior is very important because without it, functions that return functions wouldn’t be very useful. So it’s important we understand how they work and what this behavior is called.

  • 这种行为非常重要,因为没有它,返回函数的函数将不会非常有用。 因此,重要的是我们要了解它们的工作方式以及所谓的行为。

This behavior is called a Closure.

  • 此行为称为Closure。

Closures

image.png

Here’s a contrived example of functions that use closures:

  • 这是一个使用闭包的函数的人为例子:
image.png

In this example, child has access to its variables, the parent’s variables and the grandParent’s variables.

  • 在此示例中,child可以访问其变量,父变量和grandParent变量。

The parent has access to its variables and grandParent’s variables.

  • 父级可以访问其变量和grandParent的变量。

The grandParent only has access to its variables.

  • grandParent只能访问其变量。

(See pyramid above for clarification.)
-(见上面的金字塔以便澄清。)

Here’s an example of its use:

  • 以下是其使用示例:
image.png

Here, parentFunc keeps the parent’s scope alive since grandParent returns parent.

  • 这里,parentFunc保持父级的范围,因为grandParent返回父级。

Similarly, childFunc keeps the child’s scope alive since parentFunc, which is just parent, returns child.

  • 类似地,childFunc使子节点的范围保持活动,因为parentFunc(只是父节点)返回child。

When a function is created, all of the variables in its scope at the time of creation are accessible to it for the lifetime of the function. A function exists as long as there still a reference to it. For example, child’s scope exists as long as childFunc still references it.

  • 创建函数时,在函数生命周期内,可以访问其创建时范围内的所有变量。 只要仍然存在对它的引用,就存在一个函数。 例如,只要childFunc仍引用它,子范围就存在。

A closure is a function’s scope that’s kept alive by a reference to that function.
Note that in Javascript, closures are problematic since the variables are mutable, i.e. they can change values from the time they were closed over to the time the returned function is called.

  • 闭包是一个函数的作用域,它通过对该函数的引用而保持活跃。
    请注意,在Javascript中,闭包是有问题的,因为变量是可变的,即它们可以从关闭它们到调用返回函数的时间更改值。

Thankfully, variables in Functional Languages are Immutable eliminating this common source of bugs and confusion.

  • 值得庆幸的是,Functional Languages中的变量是不可变的,消除了这种常见的错误和混淆源。

Enough for now.

  • 够了。

In subsequent parts of this article, I’ll talk about Functional Composition, Currying, common functional functions (e.g map, filter, fold etc.), and more.

  • 在本文的后续部分中,我将讨论功能组合,Currying,常用功能功能(例如地图,过滤器,折叠等)等。

你可能感兴趣的:(02. So You Want to be a Functional Programmer (Part 2))