Functional programming from the point of view of EcmaScript. Pure functions, lambdas, immunity

Hello, Habr!



Today we will begin to speak on a very important topic - functional programming. The importance of FP in modern web development is difficult to overestimate. The architecture of any large-scale modern project includes user-defined function libraries, and there will be mandatory questions on FI at an interview at any level.



Introduction to Functional Programming



Functional programming (FP) is a way of organizing code by writing a set of functions.



EcmaScript, being a multi-paradigm programming language, implements, among others, a functional paradigm. This means that functions in ES are data and can be passed to functions, returned from functions, and can accept functions themselves. Those. functions in ES are first class functions .



The following definitions follow from this:



Functional argument (funarg) - an argument whose value is a function.



A higher-order function (FWP, higher-order-funtion, hof) is a function that accepts functions as arguments.



Functions with a functional value (Function valued functions) - a function that returns a function.



All these types of functions are conditionally combined into functions of the first class, and, as follows from the definition above, in ES all functions are objects of the first class.



Pure functions - ideal for functional programming



Pure functions (PF) - always return a predicted result.

PF Properties:





An example of a pure function:



const add = (x,y) => x+y;
      
      





A good example of function impurity is:



 var first; var second; function testFn() { var a = 10; first = function() { return ++a; } second = function() { return --a; } a = 2; first();//3 } testFn(); first();//4 second();//3
      
      





Imagine how complicated it is to write tests for this example and how much it simplifies for pure functions!



Impure functions are characterized by a time-varying external state that complicates the maintenance, understanding, and testing of code.



On the contrary, pure functions are always readable, testable, simplify the parallelization of calculations, and are easy to reuse.



I think you noticed that in the examples on pure functions, I switched to ES6 syntax. This was done deliberately. This function syntax is called "arrow functions", but in fact it is an implementation of mathematical abstraction, invented a long time ago. About it further.



Lambda - functions



This is what this arrow form of writing is called in mathematics and some other programming languages. Functional programming is very closely related to mat. analysis, so do not be surprised.



The term Lambda calculus was introduced back in the 1930s by Alonzo Church. In essence, lambda calculus is nothing more than a formal form of describing a mathematical equation. More details here .



In ES, a lambda function often implements a closure:



 const add = x => y => x + y;
      
      





Short and concise. The add function is a lambda that takes an argument x, stores it in a closure, and returns a function.



Compare with this code:



 funtion add(x) { return function (y) { return x + y; } }
      
      





Obviously, the first option looks better.



Immunity



Immutable (immutable, immunity) is an object whose state cannot be changed after creation. The result of any modification of such an object will always be a new object, while the old object will not change.



Immutability is the golden grail of functional programming.



Consider an example:



 const impureAddProp = (key, value, object) => { object[key] = value;//   }; const User= { name: 'Alex' }; impureAddProp ('isAdmin', true, User);
      
      





As you can see, in this example, we mutated the User object by adding a property to it. Now the User object is a kind of “shared state” for the impureAddProp function and other functions that will mutate it. This approach is harder to test because When changing any function interacting with a shared state, one should always bear in mind possible errors in other functions.



From the point of view of functional programming, it would be correct like this:



 const pureAddProp = (key, value, object) => ({ ...object, [key]: value }); const User= { name: 'Alex' }; const Admin= pureAddProp ('isAdmin', true, User);
      
      





So the User object will remain unchanged. We are modifying a copy of the data, which is always safe.



Conclusion



Today we have examined several important theoretical concepts. We got acquainted with pure functions, lambda form of recording functions and the concept of immutability in fp. However, this article is a kind of introduction. The main ideas, techniques and “hard parts” of functional programming will be in the following articles.



Functional programming is implemented by many libraries. This is rambda, and lodash, and many others. In a real project, you, of course, will use them. Under the hood of any libraries, there will still be the same native javascript, so in the next articles we will analyze the FP, realizing all its concepts on native JS.



P.S



Starting to write articles, I had in mind the following plan:





To date, head articles in three areas have already been written:



  1. this and ScopeChain in EcmaScript - here I described such key concepts of the specification as the execution context, the this keyword, and the ScopeChain context property (scope chain). In the framework of this direction, my article on the Lexical environment and Closure was published literally today.
  2. A look from EcmaScript on the general theory of OOP - the difference between static class typing and dynamic prototype organization was described here, the delegating model and duck typing are disassembled
  3. Elegant patterns in modern JavaScript (Bill Sourour compilation series on the cycle) - here are two patterns that can be useful in some situations. My approach in terms of patterns is quite simple: it is better to know as many patterns as possible, because sooner or later come in handy


And now it is the turn of functional programming. In the future, I will write articles in the continuation of each of these areas. For example, the next article will be about the key concepts of OOP: encapsulation, abstraction, impurities (and strokes), interfaces, etc. ... I also plan to talk about how OOP in ES is implemented under the hood, i.e. about the properties of [[Prototype]], [[Class]] and much more. Talk about how v8 creates entities and instances of classes, functions.



A lot of questions come up in the comments, so I would like to explain the goals that I set for my articles. I do not write tutorials or review documentation. In my opinion, this makes no sense. I do not advise you for certain instruments or patterns, their choice is entirely up to you.



In the articles, I either review the concepts, tell how they are arranged under the hood (in my opinion, this improves the understanding of what we write and why we write this way), or I talk about some things that broaden my horizons. In my opinion this is very important. Take a look at companies like Yandex or Edadil, they constantly talk about some kind of original ideas. Either these are bitmaps in the react, then the vue application is almost completely on es6 classes. Most web developers would never have thought of such a thing. This requires a broad outlook.



I myself studied and study the web in this way, i.e. after reading a tutorial or a dock, I try to understand how the described tool works under the hood, to understand its internal mechanics.



Until future articles, friends!



All Articles