美文网首页
01. So You Want to be a Function

01. So You Want to be a Function

作者: ngugg | 来源:发表于2018-10-30 18:10 被阅读11次

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

    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.

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

    When we first learned to drive, we struggled. It sure looked easy when we saw other people doing it. But it turned out to be harder than we thought.

    • 当我们第一次学会驾驶时,我们挣扎着。 当我们看到其他人这样做时,看起来很容易。 但结果却比我们想象的更难。

    We practiced in our parent’s car and we really didn’t venture out on the highway until we had mastered the streets in our own neighborhood.

    • 我们在父母的车上练习,在我们掌握了自己街区的街道之前,我们真的没有在高速公路上冒险。

    But through repeated practice and some panicky moments that our parents would like to forget, we learned to drive and we finally got our license.

    • 但是通过反复练习和我们父母想要忘记的一些恐慌时刻,我们学会开车,最后我们获得了执照。

    With our license in hand, we’d take the car out any chance we could. With each trip, we got better and better and our confidence went up. Then came the day when we had to drive someone else’s car or our car finally gave up the ghost and we had to buy a new one.
    -有了我们的许可证,我们会尽可能地把车开出去。 随着每次旅行,我们越来越好,我们的信心也随之增强。 那天我们不得不驾驶别人的车,或者我们的车终于放弃了鬼魂,我们不得不买一个新的。

    What was it like that first time behind the wheel of a different car? Was it like the very first time behind the wheel? Not even close. The first time, it was all so foreign. We’ve been in a car before that, but only as a passenger. This time we were in the driver seat. The one with all the controls.

    • 第一次在另一辆车的车轮后面是什么感觉? 这是第一次驾驶这辆车吗? 差远了。 第一次,这一切都是如此的陌生。 我们之前一直在开车,但只是作为一名乘客。 这次我们在驾驶员座位上。 具有所有控件的那个。

    But when we drove our second car, we simply asked ourselves a few simple questions like, where does the key go, where are the lights, how do you use the turn signals and how do you adjust the side mirrors.

    • 但是当我们驾驶第二辆车时,我们只是问自己一些简单的问题,比如钥匙在哪里,灯在哪里,你如何使用转向灯以及如何调整后视镜。

    After that, it was pretty smooth sailing. But why was this time so easy compared to the first time?

    • 在那之后,航行非常顺利。 但与第一次相比,为什么这次这么容易?

    That’s because the new car was pretty much like the old car. It had all the same basic things that a car needs and they were pretty much in the same place.

    • 那是因为这辆新车非常像旧车。 它拥有汽车所需的所有基本功能,而且它们几乎都在同一个地方。

    A few things were implemented differently and maybe it had a few additional features, but we didn’t use them the first time we drove or even the second. Eventually, we learned all the new features. At least the ones we cared about.

    • 有些东西的实现方式不同,可能还有一些额外的功能,但我们第一次开车甚至第二次都没有使用它们。 最终,我们学到了所有新功能。 至少我们关心的是那些。

    Well, learning programming languages is sort of like this. The first is the hardest. But once you have one under your belt, subsequent ones are easier.

    • 那么,学习编程语言有点像这样。 第一个是最难的。 但是一旦你掌握了一个,后续的更容易。

    When you first start a second language, you ask questions like, “How do I create a module? How do you search an array? What are the parameters of the substring function?”

    • 当您第一次启动第二语言时,您会问“我如何创建模块? 你如何搜索阵列? 子串函数的参数是什么?“

    You’re confident that you can learn to drive this new language because it reminds you of your old language with maybe a few new things to hopefully make your life easier.

    • 你有信心可以学习驾驶这种新语言,因为它会让你想起你的旧语言,或许还有一些新的东西可以让你的生活更轻松。

    Your First Spaceship

    • 你的第一艘宇宙飞船
    image.png

    Whether you’ve been driving one car your whole life or dozens of cars, imagine that you’re about to get behind the wheel of a spaceship.

    • 无论你是一辈子驾驶一辆汽车还是几十辆汽车,想象一下你即将驾驶太空船。

    If you were going to fly a spaceship, you wouldn’t expect your driving ability on the road to help you much. You’d be starting over from square zero. (We are programmers after all. We count starting at zero.)

    • 如果你要乘坐宇宙飞船,你不会指望你在路上的驾驶能力对你有所帮助。 你将从方形零开始。 (毕竟我们是程序员。我们从零开始计算。)

    You would begin your training with the expectation that things are very different in space and that flying this contraption is very different than driving on the ground.

    • 你会开始你的训练,期望太空中的事物非常不同,并且飞行这个装置与在地面上驾驶非常不同。

    Physics hasn’t changed. Just the way you navigate within that same Universe.

    • 物理学没有改变。 只是你在同一个宇宙中导航的方式。

    And it’s the same with learning Functional Programming. You should expect that things will be very different. And that much of what you know about programming will not translate.

    • 学习函数式编程也是如此。 你应该期待事情会有很大的不同。 而你所知道的关于编程的很多东西都不会翻译。

    Programming is thinking and Functional Programming will teach you to think very differently. So much so, that you’ll probably never go back to the old way of thinking.

    • 编程思考,功能编程将教你不同的思考方式。 这么多,你可能永远不会回到原来的思维方式。

    Forget Everything You Know

    • 忘掉你所知道的一切
    image.png

    People love saying this phrase, but it’s sort of true. Learning functional programming is like starting from scratch. Not completely, but effectively. There are lots of similar concepts but it’s best if you just expect that you have to relearn everything.

    • 人们喜欢说这句话,但这有点真实。 学习函数式编程就像从头开始。 不完全,但有效。 有很多类似的概念,但如果你只是希望你必须重新学习所有东西,这是最好的。

    With the right perspective you’ll have the right expectations and with the right expectations you won’t quit when things get hard.

    • 从正确的角度来看,你会有正确的期望,并且在事情变得艰难时,你不会放弃正确的期望。

    There are all kinds of things that you’re used to doing as a programmer that you cannot do any more with Functional Programming.

    • 作为程序员,你曾经做过各种各样的事情,你不能再使用函数式编程了。

    Just like in your car, you used to backup to get out of the driveway. But in a spaceship, there is no reverse. Now you may think, “WHAT? NO REVERSE?! HOW THE HELL AM I SUPPOSED TO DRIVE WITHOUT REVERSE?!”

    • 就像在你的车里一样,你曾经用来备份离开车道。 但在宇宙飞船中,没有任何逆转。 现在你可能会想,“什么? 没有倒退?! 我怎么支持驾驶而没有倒车?!“

    Well, it turns out that you don’t need reverse in a spaceship because of its ability to maneuver in three dimensional space. Once you understand this, you’ll never miss reverse again. In fact, someday, you’ll think back at how limiting the car really was.

    • 嗯,事实证明,由于它能够在三维空间中进行机动,因此你不需要在宇宙飞船中进行反向操作。 一旦你理解了这一点,你将再也不会错过逆转。 事实上,总有一天,你会回想起如何限制汽车。

    Learning Functional Programming takes a while. So be patient.

    • 学习函数式编程需要一段时间。 所以要耐心等待。

    So let’s exit the cold world of Imperative Programming and take a gentle dip into the hot springs of Functional Programming.

    • 因此,让我们退出命令式编程的冷酷世界,轻轻地进入函数式编程的温泉。

    What follows in this multi-part article are Functional Programming Concepts that will help you before you dive into your first Functional Language. Or if you’ve already taken the plunge, this will help round out your understanding.

    • 本系列文章的后续内容是函数式编程概念,它将在您深入了解您的第一个函数式语言之前为您提供帮助。 或者,如果你已经采取了暴跌,这将有助于完善你的理解。

    Please don’t rush. Take your time reading from this point forward and take the time to understand the coding examples. You may even want to stop reading after each section to let the ideas sink in. Then return later to finish.

    • 请不要急于求成。 花点时间从这一点开始阅读并花时间了解编码示例。 您甚至可能希望在每个部分之后停止阅读以让想法陷入其中。然后返回完成。

    The most important thing is that you understand.

    • 最重要的是你了解。

    Purity

    image.png

    When Functional Programmers talk of Purity, they are referring to Pure Functions.

    • 当函数式程序员谈论纯度时,他们指的是纯函数。

    Pure Functions are very simple functions. They only operate on their input parameters.

    • 纯函数是非常简单的函数。 它们仅对输入参数进行操作。

    Here’s an example in Javascript of a Pure Function:

    • 这是纯函数Javascript中的一个例子:
    var z = 10;
    function add(x, y) {
        return x + y;
    }
    

    Notice that the add function does NOT touch the z variable. It doesn’t read from z and it doesn’t write to z. It only reads x and y, its inputs, and returns the result of adding them together.

    • 请注意,add函数不会触及z变量。 它不从z读取,也不写入z。 它只读取x和y,它的输入,并返回将它们加在一起的结果。

    That’s a pure function. If the add function did access z, it would no longer be pure.

    • 这是一个纯粹的功能。 如果add函数确实访问了z,那么它将不再是纯粹的。

    Here’s another function to consider:

    • 这是另一个要考虑的功能:
    function justTen() {
        return 10;
    }
    

    If the function, justTen, is pure, then it can only return a constant. Why?

    • 如果函数justTen是纯的,那么它只能返回一个常量。 为什么?

    Because we haven’t given it any inputs. And since, to be pure, it cannot access anything other than its own inputs, the only thing it can return is a constant.

    • 因为我们没有给它任何输入。 而且,既然是纯粹的,除了自己的输入之外它不能访问任何东西,它唯一可以返回的就是常量。

    Since pure functions that take no parameters do no work, they aren’t very useful. It would be better if justTen was defined as a constant.

    • 由于不带参数的纯函数不起作用,因此它们不是很有用。 如果justTen被定义为常量会更好。

    Most useful Pure Functions must take at least one parameter.

    • 最有用的Pure Functions必须至少使用一个参数。

    Consider this function:

    • 考虑这个功能:
    function addNoReturn(x, y) {
        var z = x + y
    }
    

    Notice how this function doesn’t return anything. It adds x and y and puts it into a variable z but doesn’t return it.

    • 注意这个函数怎么不返回任何东西。 它添加x和y并将其放入变量z但不返回它。

    It’s a pure function since it only deals with its inputs. It does add, but since it doesn’t return the results, it’s useless.

    • 这是一个纯函数,因为它只处理它的输入。 它确实添加,但由于它不返回结果,它是无用的。

    All useful Pure Functions must return something.

    • 所有有用的Pure Functions都必须返回一些内容

    Let’s consider the first add function again:

    • 让我们再考虑第一个添加函数:
    function add(x, y) {
        return x + y;
    }
    console.log(add(1, 2)); // prints 3
    console.log(add(1, 2)); // still prints 3
    console.log(add(1, 2)); // WILL ALWAYS print 3
    

    Notice that add(1, 2) is always 3. Not a huge surprise but only because the function is pure. If the add function used some outside value, then you could never predict its behavior.

    • 请注意,add(1,2)总是为3.不是一个巨大的惊喜,只是因为函数是纯粹的。 如果add函数使用了一些外部值,那么你永远无法预测它的行为。

    Pure Functions will always produce the same output given the same inputs.

    • 在相同输入的情况下,纯函数将始终生成相同的输出。

    Since Pure Functions cannot change any external variables, all of the following functions are impure:

    • 由于Pure Functions不能更改任何外部变量,因此以下所有函数都是不纯的:

    writeFile(fileName);
    updateDatabaseTable(sqlCmd);
    sendAjaxRequest(ajaxRequest);
    openSocket(ipAddress);

    All of these function have what are called Side Effects. When you call them, they change files and database tables, send data to a server or call the OS to get a socket. They do more than just operate on their inputs and return outputs. Therefore, you can never predict what these functions will return.

    • 所有这些函数都具有所谓的副作用。 当您调用它们时,它们会更改文件和数据库表,将数据发送到服务器或调用操作系统以获取套接字。 他们所做的不仅仅是操作他们的输入和返回输出。 因此,您永远无法预测这些函数将返回什么。

    Pure functions have no side effects.

    • 纯功能没有副作用。

    In Imperative Programming Languages such as Javascript, Java, and C#, Side Effects are everywhere. This makes debugging very difficult because a variable can be changed anywhere in your program. So when you have a bug because a variable is changed to the wrong value at the wrong time, where do you look? Everywhere? That’s not good.

    • 在诸如Javascript,Java和C#等命令式编程语言中,副作用无处不在。 这使调试变得非常困难,因为变量可以在程序中的任何位置更改。 因此当你有一个错误,因为变量在错误的时间被更改为错误的值,你在哪里看? 到处? 这不好。

    At this point, you’re probably thinking, “HOW THE HELL DO I DO ANYTHING WITH ONLY PURE FUNCTIONS?!”

    • 在这一点上,你可能会想,“我怎么做任何只有纯函数的东西?!”

    In Functional Programming, you don’t just write Pure Functions.

    • 在功能编程中,您不仅要编写纯函数。

    Functional Languages cannot eliminate Side Effects, they can only confine them. Since programs have to interface to the real world, some parts of every program must be impure. The goal is to minimize the amount of impure code and segregate it from the rest of our program.

    • 函数语言不能消除副作用,它们只能限制它们。 由于程序必须与现实世界接口,因此每个程序的某些部分必须是不纯的。 目标是尽量减少不纯的代码数量,并将其与我们的其他程序隔离开来。

    Immutability: 不变性


    image.png

    Do you remember when you first saw the following bit of code:

    • 你还记得你第一次看到下面的代码时:
    var x = 1;
    x = x + 1;
    

    And whoever was teaching you told you to forget what you learned in math class? In math, x can never be equal to x + 1.

    • 谁教你的人告诉你要忘记你在数学课上学到的东西? 在数学中,x永远不能等于x + 1。

    But in Imperative Programming, it means, take the current value of x add 1 to it and put that result back into x.

    • 但是在命令式编程中中,它意味着,将x的当前值加1,并将该结果放回x中。

    Well, in functional programming, x = x + 1 is illegal. So you have to remember what you forgot in math… Sort of.

    • 那么,在函数式编程中,x = x + 1是非法的。 所以你必须记住你在数学中忘记的东西......排序。

    There are no variables in Functional Programming.

    • 功能编程中没有变量。

    Stored values are still called variables because of history but they are constants, i.e. once x takes on a value, it’s that value for life.

    • 由于历史记录,存储的值仍称为变量,但它们是常量,即一旦x取值,它就是生命值。

    Don’t worry, x is usually a local variable so its life is usually short. But while it’s alive, it can never change.

    • 别担心,x通常是局部变量,所以它的寿命通常很短。 但它虽然活着,却永远无法改变。

    Here’s an example of constant variables in Elm, a Pure Functional Programming Language for Web Development:

    • 以下是Elm中常量变量的示例,这是一种用于Web开发的纯函数式编程语言:
    addOneToSum y z =
        let
            x = 1
        in
            x + y + z
    

    If you’re not familiar with ML-Style syntax, let me explain. addOneToSum is a function that takes 2 parameters, y and z.

    • 如果您不熟悉ML-Style语法,我解释一下。 addOneToSum是一个带有2个参数y和z的函数。

    Inside the let block, x is bound to the value of 1, i.e. it’s equal to 1 for the rest of its life. Its life is over when the function exits or more accurately when the let block is evaluated.

    • 在let块内,x被绑定到值1,即它在其余生中等于1。 当函数退出时,它的寿命结束,或者在评估let块时更准确。

    Inside the in block, the calculation can include values defined in the let block, viz. x. The result of the calculation x + y + z is returned or more accurately, 1 + y + z is returned since x = 1.

    • 在in块中,计算可以包括let块中定义的值,即。 X。 返回或更准确地返回计算结果x + y + z,因为x = 1,所以返回1 + y + z。

    Once again, I can hear you ask “HOW THE HELL AM I SUPPOSED TO DO ANYTHING WITHOUT VARIABLES?!”

    再一次,我可以听到你问“我怎么做我没有任何变量做什么?!”

    Let’s think about when we want to modify variables. There are 2 general cases that come to mind: multi-valued changes (e.g. changing a single value of an object or record) and single-valued changes (e.g. loop counters).

    • 让我们考虑一下我们想要修改变量的时间。 可以想到两种一般情况:多值变化(例如,改变对象或记录的单个值)和单值变化(例如循环计数器)。

    Functional Programming deals with changes to values in a record by making a copy of the record with the values changed. It does this efficiently without having to copy all parts of the record by using data structures that makes this possible.

    • 函数式编程通过使用更改的值创建记录的副本来处理记录中值的更改。 它可以有效地执行此操作,而无需使用可实现此目的的数据结构来复制记录的所有部分。
    详细解释:
    
    比如一个学生
    name:张三   ,age: 18, score: 90
    name:张三   ,age: 20, score: 90
    
    Functional Programming deals with changes to values in a record 
    
    函数式编程  处理记录中 值的更改。
    
     by making a copy of the record    with the values changed.
    
    通过使用更改的值创建记录的副本
    
     It does this efficiently 
    它可以有效地执行此操作
    
    
    without having to copy all parts of the record 
     而无需复制记录的所有部分
    
    
    by using data structures that makes this possible.
    使用可实现此目的的数据结构
    

    Functional programming solves the single-valued change in exactly the same way, by making a copy of it.

    • 函数式编程通过复制它来以完全相同的方式解决单值更改。

    Oh, yes and by not having loops.

    • 哦,是的,没有循环。

    “WHAT NO VARIABLES AND NOW NO LOOPS?! I HATE YOU!!!”

    • “什么都不变,现在没有?” 我恨你!!!”

    Hold on. It’s not like we can’t do loops (no pun intended), it’s just that there are no specific loop constructs like for, while, do, repeat, etc.

    • 坚持,稍等。 这不像我们不能做循环(没有双关语),只是没有特定的循环结构,如for,while,do,repeat等。

    Functional Programming uses recursion to do looping.

    • Functional Programming使用递归来进行循环。

    Here are two ways you can do loops in Javascript:

    • 以下是Javascript中可以执行循环的两种方法:
    // simple loop construct
    var acc = 0;
    for (var i = 1; i <= 10; ++i)
        acc += I;
    console.log(acc); // prints 55
    
    // without loop construct or variables (recursion)
    function sumRange(start, end, acc) {
        if (start > end)
            return acc;
        return sumRange(start + 1, end, acc + start)
    }
    console.log(sumRange(1, 10, 0)); // prints 55
    

    Notice how recursion, the functional approach, accomplishes the same as the for loop by calling itself with a new start (start + 1) and a new accumulator (acc + start). It doesn’t modify the old values. Instead it uses new values calculated from the old.

    • 注意递归,函数方法如何通过使用新的start(start + 1)和新的accumulator(acc + start)调用自身来完成与for循环相同的操作。 它不会修改旧值。 相反,它使用从旧计算的新值。

    Unfortunately, this is hard to see in Javascript even if you spend a little time studying it, for two reasons. One, the syntax of Javascript is noisy and two, you’re probably not used to thinking recursively.

    • 不幸的是,这很难在Javascript中看到,即使你花了一点时间研究它,原因有两个。 一,Javascript的语法很吵,两个,你可能不习惯递归思考。

    In Elm, it’s easier to read and, therefore, understand:

    • 在榆树中,它更容易阅读,因此,理解:
    sumRange start end acc =
        if start > end then
            acc
        else
            sumRange (start + 1) end (acc + start) 
    

    Here’s how it runs: 以下是它的运行方式:

    sumRange 1 10 0 =      -- sumRange (1 + 1)  10 (0 + 1)
    sumRange 2 10 1 =      -- sumRange (2 + 1)  10 (1 + 2)
    sumRange 3 10 3 =      -- sumRange (3 + 1)  10 (3 + 3)
    sumRange 4 10 6 =      -- sumRange (4 + 1)  10 (6 + 4)
    sumRange 5 10 10 =     -- sumRange (5 + 1)  10 (10 + 5)
    sumRange 6 10 15 =     -- sumRange (6 + 1)  10 (15 + 6)
    sumRange 7 10 21 =     -- sumRange (7 + 1)  10 (21 + 7)
    sumRange 8 10 28 =     -- sumRange (8 + 1)  10 (28 + 8)
    sumRange 9 10 36 =     -- sumRange (9 + 1)  10 (36 + 9)
    sumRange 10 10 45 =    -- sumRange (10 + 1) 10 (45 + 10)
    sumRange 11 10 55 =    -- 11 > 10 => 55
    55
    

    You’re probably thinking that for loops are easier to understand. While that’s debatable and more likely an issue of familiarity, non-recursive loops require Mutability, which is bad.

    • 您可能认为for循环更容易理解。 虽然这是有争议的,更可能是熟悉的问题,但非递归循环需要Mutability,这很糟糕。

    I haven’t entirely explained the benefits of Immutability here but check out the Global Mutable State section in Why Programmers Need Limits to learn more.

    • 我还没有完全解释Immutability在这里的好处,但请查看为什么程序员需要限制的全局可变状态部分以了解更多信息。

    One obvious benefit is that if you have access to a value in your program, you only have read access, which means that no one else can change that value. Even you. So no accidental mutations.

    • 一个明显的好处是,如果您有权访问程序中的值,那么您只具有读取权限,这意味着没有其他人可以更改该值。 即便是你。 所以没有偶然的突变。

    Also, if your program is multi-threaded, then no other thread can pull the rug out from under you. That value is constant and if another thread wants to change it, it’ll have create a new value from the old one.

    • 此外,如果您的程序是多线程的,那么没有其他线程可以从您的下方拉出地毯。 该值是常量,如果另一个线程想要更改它,它将从旧值创建一个新值。

    Back in the mid 90s, I wrote a Game Engine for Creature Crunch and the biggest source of bugs was multithreading issues. I wish I knew about immutability back then. But back then I was more worried about the difference between a 2x or 4x speed CD-ROM drives on game performance.

    • 早在90年代中期,我为Creature Crunch编写了一个游戏引擎,最大的错误来源是多线程问题。 我希望我当时知道不变性。 但那时我更担心2倍速或4倍速CD-ROM驱动器在游戏性能上的差异。

    Immutability creates simpler and safer code.
    不变性可以创建更简单,更安全的代码。

    image.png

    Enough for now.

    • 够了。

    In subsequent parts of this article, I’ll talk about Higher-order Functions, Functional Composition, Currying and more.

    • 在本文的后续部分中,我将讨论高阶函数,函数组合,Currying等。

    相关文章

      网友评论

          本文标题:01. So You Want to be a Function

          本文链接:https://www.haomeiwen.com/subject/ptkgtqtx.html