你想成为一个 函数编程者么(第一部分)

@sakila1012 2018-01-22 09:13:49发表于 sakila1012/blog

你想成为一个 函数编程者么(第一部分)

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.

Learning to Drive


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?”
当你第一次开始学习第二门语言时,你可能会问类似的问题,“如何创建一个模块?你如何搜索数组?substring 函数的参数是什么?”

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


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


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.



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:

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。仅仅读它的输入 xy,然后一块返回他们求和的结果。

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.

Most useful Pure Functions must take at least one parameter.

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.
注意,这个函数没有任何返回。它将 xy 赋给变量 z,但是没有返回 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.

Let’s consider the first add function again:
让我们再次看看第一个函数 add

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。不是很大的惊喜,只是因为这个函数是纯函数的。

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:


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.



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 =
        x = 1
        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风格的语法,让我来给你解释。

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.

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.


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.

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.


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.

Functional Programming uses recursion to do looping.

Here are two ways you can do loops in 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.

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.

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

sumRange start end acc =
    if start > end then
        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

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.

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.

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.

Immutability creates simpler and safer code.

My Brain!!!!


Enough for now.

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

Up Next: Part 2

If you liked this, click the? below so other people will see this here on Medium.
如果你喜欢,点击这?下面,其他人会在 Medium 上看到这个

If you want to join a community of web developers learning and helping each other to develop web apps using Functional Programming in Elm please check out my Facebook Group, Learn Elm Programming https://www.facebook.com/groups/learnelm/
如果你想加入 web 开发者学习社区,请在 ELM 函数编程使用相互帮助开发Web应用程序,请检查我的脸谱网组,学习 ELM 的编程 https://www.facebook.com/groups/learnelm/

My Twitter: @cscalfani

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.