天天看点

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

java 函数编程

The mystic term of Functional Programming (FP) must be familiar to any JS developer. The first impression when we say “JS supports functional programming paradigm” or “JS is a Functional programming language”, could be, well I use functions in JS, so I’m already doing Functional programming. This is the myth that we’re going to bust together.

任何JS开发人员都必须熟悉函数式编程(FP)这个神秘的术语。 当我们说“ JS支持函数式编程范例”或“ JS是一种函数式编程语言”时,第一印象可能是,我在JS中使用函数,因此我已经在进行函数式编程。 这就是我们要一起破产的神话。

You might be using the FP unknowingly but there’s a lot more to the world of Functional programming which takes years of experience to master. It involves re-wiring your thinking process to observe and implement the FP patterns in your style of writing programs.

您可能在不知不觉中使用了FP,但是函数式编程领域还有很多东西需要掌握多年的经验。 它涉及重新布线您的思维过程,以按照编写程序的方式观察和实现FP模式。

前言 (Preface)

Researching online about FP can leave you inundated with mathematical information that you have no awareness of. This is probably why it’s not that popular among the developer community (due to the steep learning curve involved). Even if you learn some of FP concepts in Javascript, like currying or composing, you may find yourself wondering “How the heck can I use it in my real-world projects?” That’s the same situation I found myself in when I learned about currying (which I wrote an article two years back here wherein I explained it with the help of a contrived example). Guess what, the most common question was, “How and when can I use it in the real world? And is that all Functional Programming is all about?” We’ll address all these questions here.

在线研究FP可能会让您被无知的数学信息所淹没。 这可能是为什么它在开发人员社区中不那么受欢迎的原因(由于涉及到陡峭的学习曲线)。 即使您学习了Java FP的某些FP概念(例如,curry或composition),也可能会发现自己想知道“我该如何在现实世界的项目中使用它?” 这是我在学习curry时遇到的情况(两年前我在这里写了一篇文章,其中我在一个人为的例子的帮助下对此进行了解释)。 猜猜最常见的问题是:“如何以及何时在现实世界中使用它? 而且,所有的函数式编程都是这样吗?” 我们将在这里解决所有这些问题。

But before we go any further, we need to understand the basic pillars of FP and why is it worth learning FP in general.

但是,在进一步研究之前,我们需要了解FP的基本Struts,以及为什么值得总体学习FP。

什么是函数式编程? (What is Functional Programming?)

Functional Programming (FP) is a programming paradigm or a way/style of programming which has the following characteristics:

功能编程(FP)是一种编程范例或一种编程方式/风格,具有以下特征:

  • We build programs by composing reusable “Pure functions”.

    我们通过构成可重用的“ 纯函数 ”来构建程序。

  • Write declarative code instead of imperative.

    编写声明性代码而不是命令性代码。

It’s more of a way of adapting your brain to think of the FP patterns in your programs.

它更多是一种使大脑适应程序中FP模式的方法。

We’ll learn about all of this using practical examples in a moment.

稍后我们将通过实际示例来了解所有这些信息。

为什么要进行函数式编程? (Why Functional Programming?)

Below are the convincing reasons to learn FP:

以下是学习FP的令人信服的理由:

命令式与声明式代码 (Imperative vs Declarative code)

Consider this code snippet which gets the best products out of an array of products.

考虑一下此代码片段,它可以从一系列产品中获得最好的产品。

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

It does the job, it gives the correct output. But we had to read through the whole code like a story or a series of steps we’re telling the computer to execute in order to make meaning out of it. A computer is excellent at this job of executing programs step by step as a sequence of instructions. And above is a classical example of Procedural programming. So, even though the keyword “function” is used here, it doesn’t make it qualify for Functional Programming because it violates the fundamental principles of FP like pure functions and no side-effects.

它可以完成工作,并提供正确的输出。 但是我们必须通读整个代码,就像是一个故事或告诉计算机要执行的一系列步骤,以便从中获得意义。 计算机擅长于按指令顺序逐步执行程序。 以上是过程编程的经典示例。 因此,即使在这里使用了关键字“ function”,也不能使它符合函数式编程的要求,因为它违反了FP的基本原理,例如纯函数且没有副作用。

Let’s see a declarative version of the above snippet.

让我们看一下上面片段的声明性版本。

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

Here, we’ve modularized the code well into their individual responsibility pure functions, showing a clear link between their inputs and guaranteed correct output. The code is no longer procedural. We’re able to deduce the outcome of this code by looking at how these pieces of codes or functions are weaved into one another in plain English and returning the outcome in the end.

在这里,我们已将代码很好地模块化为它们的个人职责纯函数,从而显示了它们的输入与保证正确输出之间的清晰链接。 该代码不再是程序性的。 通过查看这些代码或函数如何用简单的英语编织在一起并最终返回结果,我们可以推断出此代码的结果。

While imperative code is easier to be understood by machines, declarative code is easier to be understood by humans.

虽然命令式代码更容易被机器理解,但是声明式代码却更容易被人理解。

Hence, you’re not only making your code more readable but also reusable by splitting into smaller chunks of individual functionality.

因此,您不仅可以拆分成较小的单个功能块,从而使代码更具可读性,而且可以重用 。

纯函数 (Pure Functions)

Continuing to the previous section on modularizing into smaller functions, we’re introducing a high level of confidence in our code. For example:

checkIfBestProduct

function returns a guaranteed boolean when being passed a product object as an input. And for a given product object, it’ll always give the same output.

继续上一部分有关模块化为较小函数的部分,我们在代码中引入了高度的信心 。 例如:当将产品对象作为输入传递时,

checkIfBestProduct

函数返回一个保证的布尔值。 对于给定的产品对象,它将始终提供相同的输出。

A pure function by definition is a function which:

根据定义, 纯函数是一种具有以下功能的函数:

  • Given the same inputs, always returns the same output, and

    给定相同的输入,总是返回相同的输出,并且

  • Has no side-effects

    没有副作用

For example, values of trigonometry functions like sin, cos, tan for corresponding inputs as angles will always be the same forever, no matter what.

例如,三角函数的值(例如sin,cos,tan)对于相应的输入(例如角度)将永远永远相同,无论如何。

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

The point is that mathematics is based on pure functions and hence it is provable. If we bring the same principle of Purity in our way of writing programs, it’ll give us a high degree of confidence and predictability and hence lesser bugs.

关键是数学是基于纯函数的,因此可以证明。 如果我们在编写程序的方式中采用相同的“ 纯度”原则,它将为我们带来高度的信心和可预测性,从而减少了错误。

Consider, this mathematical function:

考虑一下,这个数学函数:

f(x) = 2x^2 + 3
           

We know, that given an input of zero, it gives 3, an input of 1 gives 5, an input of 2 gives 11, which is a parabola if we plot it.

我们知道,给定一个输入零,它给出3,一个输入1给出5,一个输入2得到11,如果我们绘制它,它就是抛物线。

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

In programming, this mathematical function will look like this

在编程中,该数学函数将如下所示

function parabola(x) {   return 2 * Math.pow(x, 2)  + 3}
           

This pure function will give a predictable output and not cause any side-effects. It means that the output produced by this function and anywhere during its execution, it won’t pollute or mutate or affect any other part of the program. It’s completely a neat and isolated piece in itself.

此纯函数将提供可预测的输出,并且不会引起任何副作用 。 这意味着此函数及其执行过程中所产生的输出不会污染,变异或影响程序的任何其他部分。 它本身完全是一件整洁而孤立的作品。

And because it’s pure and doesn’t depend on its lexical scope, it means it’s perfect for Testing, which is another huge advantage. We don’t have to rely on dirty hacks of jasmine or jest mocks and spies here.

而且由于它是纯净的,并且不依赖于其词法范围,因此,它非常适合于Testing ,这是另一个巨大的优势。 在这里,我们不必依赖茉莉花或开玩笑的嘲笑和间谍的肮脏骇客。

expect(parabola(2)).toEqual(11); // Always true and passes
           

实施计划 (Implementing FP)

The essence of FP is how we link together these pure functions as lego blocks to build more functions on top of them to accomplish a task. These are called higher-order functions like:

FP的本质是我们如何将这些纯功能链接在一起作为乐高积木,以在它们之上构建更多功能来完成任务。 这些被称为高阶函数,例如:

(f ∘ g)(x) or f(g(x))
           
java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

If any of the functions isn’t pure, it’ll pollute all its dependencies and make them impure as well.

如果任何函数不是纯函数,它将污染其所有依赖关系,并使它们也不纯。

One way of ensuring whether the function is pure or not is through Referential transparency which means if you can replace a function call with its resulting value without changing the meaning of the program, it’s pure.

确保函数是否纯净的一种方法是通过参照透明性 ,这意味着如果可以在不改变程序含义的情况下用其结果值替换函数调用,那么它就是纯净的。

使功能纯净 (Making Functions Pure)

Function purity is a paramount requirement for FP. Sometimes, it’s just not possible to have fully pure functions in our real-world application. These are called side-effects. The most common ones are the asynchronous elements like network calls or file i/o operations which are non-deterministic. It means that even adding a console.log statement inside a function technically makes it impure because it’s an i/o operation.

功能纯度是FP的首要要求。 有时,在我们的实际应用程序中不可能完全拥有纯功能。 这些被称为副作用。 最常见的是非确定性的异步元素,例如网络调用或文件I / O操作。 这意味着即使在函数内部添加console.log语句,从技术上讲也会使它不纯,因为它是一个I / O操作。

Suppose, we have this impure function as

假设我们有这个不纯函数

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

If any problem happens in the function, for debugging it we’ll have to read the whole function. Although this is a contrived example, consider a huge imperative impure function like this in a large project. It can become really intimidating to debug or manage such a large function body.

如果函数中发生任何问题,为了进行调试,我们必须阅读整个函数。 尽管这是一个人为的示例,但在大型项目中考虑这样的巨大命令式不​​纯函数。 调试或管理如此大的功能主体可能真的很吓人。

Rather, if we could try to reduce the surface area of this function impurity, we could drastically improve the debugging times by simply focusing on the impure areas, because the pure ones would already be tested and proven to generate the correct and guaranteed outputs for given inputs. We could rather focus on the impure areas and save time.

相反,如果我们可以尝试减少此功能性杂质的表面积,则只需关注不纯的区域,就可以大大缩短调试时间,因为纯净的区域已经过测试并证明能够在给定的条件下产生正确且有保证的输出输入。 我们宁愿专注于不纯净的地方并节省时间。

The refactor for this function could look like this:

此函数的重构可能如下所示:

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

Here, the lines of code from the

getUsers

impure function has been reduced by taking out what was possible to be made pure into toJSON, buildUser, and buildUsers functions.

在这里,通过删除可能纯粹变成toJSON,buildUser和buildUsers函数的内容,减少了

getUsers

不纯函数的代码行。

组成 (Composition)

Another thing that complements well these pure functions is Function Composition or Piping

可以很好地补充这些纯功能的另一件事是功能组合或管道

Consider this contrived example of this imperative functions, wherein each step we’re storing the outcome of an arithmetic operation and passing it as an input to the next step and so on. It’s quite a common pattern to notice in your code and hence might be a good place to start refactoring it to FP as

考虑一下这个命令函数的人为设计示例,其中每个步骤我们都存储算术运算的结果,并将其作为输入传递给下一步,依此类推。 这是一种很常见的模式,需要在代码中注意,因此可能是一个开始将其重构为FP的好地方

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)
java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

组成 (Composition)

We can build a higher-order function that can take functions and its inputs and chain their output together as

我们可以构建一个高阶函数,该函数可以接受函数及其输入并将它们的输出链接在一起

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

If you observe carefully, we constructed our

processNumber

function from other small functions viz square, double and addOne. This is the real essence of functional programming. We’re writing code as an association of the functions rather than a series of imperative steps. We could reuse the functionality of squaring, doubling or adding a number elsewhere in our application and compose more functions using these. Imagine having this level of flexibility in a larger application project.

如果您仔细观察,我们会从其他小函数(即square,double和addOne)构造我们的

processNumber

函数。 这是函数式编程的真正实质。 我们将代码编写为函数的关联,而不是一系列必要的步骤。 我们可以在应用程序的其他地方重用平方,加倍或添加数字的功能,并使用这些功能组合更多的功能。 想象一下在较大的应用程序项目中具有这种灵活性。

管道 (Piping)

Similar to composing, there exists a pattern called “Pipe” which can relate to Unix Pipe if you’re familiar with it

与编写类似,存在一种称为“ Pipe”的模式,如果您熟悉它可以与Unix Pipe相关

$ wc -l * | sort -n | head -n 3
           

The above command gives the file which has the least number of lines among the three files in the current directory.

上面的命令给出的文件在当前目录的三个文件中的行数最少。

Here, we’re moving from left to right fashion. We can mimic the same behavior as

在这里,我们正在从左向右移动。 我们可以模仿与

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

Such common functions like pipe and compose are built already by the popular FP libraries like Ramda or lodash/fp and you don’t have to worry about creating them by yourself. In the case of Ramda, these are just two of the functions from a total of 257 functions! We’ll cover some of the prominent ones in part II with some real-world practical examples.

像管这些共同的职责,并撰写由喜欢流行的FP库已建成Ramda或lodash / FP ,你不必担心自己创建它们。 对于Ramda,这只是257个功能中的两个功能! 在第二部分中,我们将通过一些实际的实际例子来介绍一些突出的例子。

咖喱 (Currying)

One of the very popular buzzwords of FP you must’ve heard, most probably in a JS interview. And probably, you know the theory and you can explain someone with the help of this primitive arithmetic example as

您必须听说过的FP非常流行的流行语之一,很可能是在JS访谈中。 可能您已经了解了理论,并且可以借助此原始算术示例解释某人,如下所示:

const multiply = ( a, b ) => a * b;
const mul = curry(multiply);
mul(2)(3);
           

The question here is, why would someone want to do this. Passing arguments one by one rather than at once gives the same result, right? It sure does but we learned it because of a JS interview preparation. But now, we will see how useful this function “curry” is (which is named after the American mathematician Haskell Curry by the way).

这里的问题是,为什么有人要这样做。 一次而不是一次传递参数会得到相同的结果,对吗? 确实可以,但是我们是通过JS面试准备才学到的。 但是现在,我们将看到“ 咖喱 ”这个功能的实用性(顺便说一下,它以美国数学家Haskell Curry的名字命名)。

If you noticed above in all our examples of piping and composition, we have one requirement of the functions being unary, which means they all can accept one input only.

如果您在上面的所有管道和组成示例中都注意到了,我们对函数一元化有一个要求,这意味着它们都只能接受一个输入。

Function with two inputs is called binary, and with n inputs is called n-ary. This can be called as a function Shape.

具有两个输入的函数称为二进制,具有n个输入的函数称为n元。 这可以称为函数Shape 。

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

The shapes of the function being connected or piped need to be identical otherwise they won’t be compatible and don’t fit each other, just like the Lego pieces. Hence, it’ll be a blocker in composing functions out of function and you won’t be able to FP. This is where Currying shines and gives the advantage of modifying the function inputs to help them fit easily with others. Most of the time in a good FP project, you’ll see 95% of unary and binary functions only which makes it very suitable for composition and piping.

被连接或通过管道传递的功能的形状必须相同,否则它们将不兼容且彼此不匹配,就像乐高积木一样。 因此,这将阻碍功能与功能的组合,您将无法使用FP。 这是Currying的亮点,它具有修改功能输入以帮助他们轻松地与他人融合的优势。 在一个好的FP项目中,大多数时候,您只会看到95%的一元和二进制函数,这使其非常适合合成和管道。

Here’s a nice example

这是一个很好的例子

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

We could’ve passed add function directly here to map but because the shape of add being binary is not compatible with the unary callback map accepts, we couldn’t pass it directly.

我们可以在此处直接将add函数传递给映射,但是由于add为二进制的形状与一元回调映射接受的格式不兼容,因此我们无法直接传递它。

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

If we adjust or change the shape of the passed function by currying it and partially passing one of the parameters, we can accomplish it as above.

如果我们通过递归函数并部分传递其中一个参数来调整或更改传递函数的形状,则可以按上述方法完成。

So, in addition to adapting the shape for compatibility with other functions, there’s one more benefit currying is providing here called as “Partial Application”

因此,除了调整形状以使其与其他功能兼容之外,currying还提供了另一个好处,即所谓的“ 部分应用 ”

addToOne

function is a specialized version of the more generic

add

function. It means that one of the parameters is passed and hence this function is partially applied and needs one more argument to give a meaningful output. It’s hard to see the value in this partial application pattern in this small silly example but let's consider this generic ajax ternary function:

addToOne

函数是更通用的

add

函数的专门版本。 这意味着传递了一个参数,因此部分应用了此函数,并且需要一个以上的参数来提供有意义的输出。 在这个小小的愚蠢的示例中,很难看到此部分应用程序模式中的值,但让我们考虑一下这个通用的ajax三元函数:

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

We’re creating some specialized methods which can be used frequently in the project by partially applying some of the parameters already, which saves a lot of repetition at each invocation in the codebase.

我们正在创建一些专门的方法,这些方法可以通过部分地应用一些参数而在项目中经常使用,这可以节省代码库每次调用时的大量重复。

This can be made easier with Currying as

使用Currying as可以使此操作更容易

java 函数编程_用Java函数编程-第一部分 前言 (Preface) 什么是函数式编程? (What is Functional Programming?) 为什么要进行函数式编程? (Why Functional Programming?) 实施计划 (Implementing FP) 咖喱 (Currying) 摘要 (Summary)

If you’re curious to know how currying works under the hood, here’s the detailed article discussing all about it.

如果您想知道curring是如何进行的,那么这里有详细的文章进行了讨论。

摘要 (Summary)

These are just the fundamentals of getting started with functional programming to have you onboarded on the idea of FP. There are plenty of mystic mathematical words and jargon out there if you look for FP. The best way to learn is through examples. And, in the sequel to this article, we’ll see how we can use these patterns to convert or start writing more FP code. But until then it’s important to understand the basic principles of FP which we just discussed. There’s a lot more to FP than this.

这些只是函数式编程入门的基础,可以帮助您全面了解FP的概念。 如果您寻找FP,那么这里有很多神秘的数学单词和术语。 最好的学习方法是通过示例。 并且,在本文的续篇中,我们将看到如何使用这些模式来转换或开始编写更多FP代码。 但是直到那时,重要的是要了解我们刚刚讨论过的FP的基本原理。 FP的功能远不止于此。

Stay tuned for the next part.

请继续关注下一部分。

Thanks. Happy Coding 🤓

谢谢。 快乐编码🤓

翻译自: https://codeburst.io/functional-programming-in-javascript-part-i-2ea6c592f3c1

java 函数编程