The body of the

What is functional programming?

My understanding is that functional programming is a programming paradigm with a high degree of abstraction. Functions written in pure functional programming languages can be regarded as having no variables. Therefore, as long as the input of any function is determined, the output is determined. Functional programming is not programming with functions, nor is it traditional procedural programming. The idea is to fit complex functions into simple ones (theory of computation, or recursion, or Ramda calculus). Try to write the operation as a series of nested function calls. Functional programming I think is more mathematical or computational.

Second, the characteristics of functional programming

1. The function is “first-class citizen”

A “first class” refers to the fact that functions are equal to other data types and can be assigned to other variables, passed as arguments to another function, or returned as a value from another function. For example, the print variable in the following code is a function that can be used as an argument to another function.

var print = function(i){ console.log(i); }; [1, 2, 3]. The forEach (print);Copy the code
2. Use “expressions”, not “statements”

“Expression” is a pure operation that always returns a value; A statement is an operation that does not return a value. Functional programming requires expressions, not statements. In other words, each step is pure operation and has a return value. And the reason is because functional programming was motivated to try to compute, not to think about I/O.” The statement “reads and writes to the system and is excluded. Of course, in practice, it is impossible not to do I/O. Therefore, in the programming process, functional programming only requires to limit I/O to a minimum, do not have unnecessary read and write behavior, and maintain the simplicity of the calculation process.

3) No side effects

A “side effect” is an interaction between the inside and outside of a function (most typically, modifying the value of a global variable) that produces a result other than the operation. Functional programming emphasizes the absence of “side effects,” meaning that functions remain independent, all they do is return a new value, and nothing else, especially not changing the value of an external variable.

4. Do not change the status

In functional programming, the variables we usually understand are replaced by functions: in functional programming, variables simply represent an expression. The ‘variable’ here cannot be modified. All variables can be assigned initial values only once. (More on variables being replaced by functions below)

5. Referential transparency

Function programs also typically enforce reference transparency, meaning that if the same input is provided, the function always returns the same result. That is, the value of an expression does not depend on the global state that can change the value.

Functional programming common core concepts and techniques

1. Pure functions

What is a pure function?

A function that always gets the same output for the same input and does not have any observable side effects or depend on the state of the external environment is called a pure function. Here’s an example:

Var xs = [1, 2, 3, 4, 5]; Slice is pure because it has no side effects. For fixed inputs, the output is always fixed xs. Slice (0,3); Xs. Slice (0, 3); Xs. Splice (0, 3); // array.splice will affect the original Array, so it is not pure xs.splice(0,3);Copy the code
2. Function Corrification (advanced function)

Higher-order functions, which take functions as arguments, encapsulate the function passed in, and then return the encapsulated function to achieve a higher degree of abstraction. Call a function by passing it a set of arguments and have it return a function to handle the rest of the arguments.

Look at an example:

Function add(x, y) {return x + y; } function addX(y) {return function (x) {return x + y; }; } addX(2)(1) // 3Copy the code

Currization can be understood as a method of “preloading” functions. By passing fewer parameters, a new function that has remembered these parameters is obtained. In a sense, it is a “cache” of parameters, which is a very efficient method of writing functions.

3. Function combination

In order to solve the problem of over-nesting functions, the onion code: h(g(f(x))), we need to use “function composition”, we can change it by using Corrification, so that multiple functions are put together like building blocks.

Function composition in function programming: A combination of two pure functions returns a new function, for example:

const compose = function(f,g) { return function(x) { return f(g(x)); }; }; const toUpperCase = function(x) { return x.toUpperCase(); }; const exclaim = function(x) { return x + "!" ; }; const shout = compose( exclaim , toUpperCase ); console.log(shout("hello world")); //HELLO WORLD!Copy the code

We can simplify it for him:

const compose=(f,g)=>(x=>f(g(x))) const toUpperCase=x=>x.toUpperCase() const exclaim=x=>x+'! ' const shout=compose(exclaim,toUpperCase) console.log(shout('hello world')); //HELLO WORLD!Copy the code

composeThe order of the arguments in is arbitrary, similar to the commutative law in multiplicationxy=yxSo functional programming is close to mathematical computation.

4. Recursion and tail recursion

The last action inside a function is a function call. The return value of this call is returned directly to the function. The function calls itself, called recursion. If the tail calls itself, it is called tail recursion. Recursion requires saving a large number of call records and is prone to stack overflow errors. If you use tail recursion optimization to turn recursion into a loop, you only need to save one call record and no stack overflow errors will occur. In layman’s terms, the last step of tail recursion calls itself, and no additional operations can follow. For example, in my understanding, meeting the recursive condition is equivalent to casting the net when fishing, and then returning to oneself and closing the net when reaching the recursive boundary, namely catching the fish. Tail recursion means that the fish is already in your hand when you catch it, for example:

Function factorial(n) {if (n === 1) return 1; return n * factorial(n - 1); } factorial(n, total) {if (n === 1) return total; return factorial(n - 1, n * total); } //ES6 enforces tail recursion: return the result when the boundary condition is reachedCopy the code

Let’s take a look at recursion and tail recursion execution:

function sum(n) { if (n === 1) return 1; return n + sum(n - 1); } sum(5) (5 + sum(4)) (5 + (4 + sum(3))) (5 + (4 + (3 + sum(2)))) (5 + (4 + (3 + (2 + sum(1))))) (5 + (4 + (3 + (2 + 1)))) (5 + (4 + (3 + 3))) (5 + (4 + 6)) (5 + 10) 15Copy the code

Tail recursion:

function sum(x, total) {
    if (x === 1) {
        return x + total;
    }
    return sum(x - 1, x + total);
}
sum(5, 0)
sum(4, 5)
sum(3, 9)
sum(2, 12)
sum(1, 14)
15
Copy the code

The calculation process is linear, sum(x, total) is called once, the next stack, the relevant data and information is entered, no longer stored on the stack. When the final value is computed, sum(5,0) is returned directly to the top level. This effectively prevents stack overflow. In ECMAScript 6, we will see tail-recursive optimization, where javascript code, when interpreted as machine code, will look like while, that is, with both mathematical expressiveness and the efficiency of while.

5. Lazy calculation (evaluation)

In lazy computation, the expression is not evaluated immediately when it is bound to a variable, but when the evaluator needs to produce the value of the expression. Deferred computation allows you to write functions that potentially produce infinite output. Because you don’t compute more than the rest of the program needs, you don’t need to worry about out-of-memory errors caused by infinite computations. To put it simply:

Take what you need, do not more than you can do

So here’s my own implementation of simple lazy evaluation and I’ll write a minimal implementation of lazy evaluation in JavaScript official documentation official documentation

Summary of functional programming

1. Every symbol in functional programming is const, so no function has side effects. No one can change anything at run time, and no function can change what value outside its scope to be used by other functions. This means that the only thing that determines the result of a function’s execution is its return value, and the only thing that affects its return value is its arguments. 2. Functional programming does not consider deadlocks because it does not modify variables, so there is no problem of “locking” threads. We don’t have to worry about one thread’s data being modified by another, so we can feel comfortable spreading the work across multiple threads. 3. In functional programming, all states are parameters passed to the function, and parameters are stored on the stack. This feature makes hot deployment of software very easy. Just get a DIFF by comparing the running code with the new code, and then update the existing code with that DIFF, and hot deployment of the new code is complete.

reference

A guide to JavaScript functional programming