Recently, I talked to some students about functional programming. Many of them thought it sounded fancy, but they didn’t know how to use it. So I took the time to comb, the usual work used functional programming cases and ideas sorted out, I believe that after reading this article, we can quickly get started functional programming.

Functional programming is now widely used in almost every framework and language.

  • React-vue hooks
  • Packaging tools: Webpack-chain usage of Webpack.
  • Tool libraries: Underscore, Lodash, Ramda.
  • Deployment mode: Serverless.
  • Back end: lamda expressions in Java and c#.

This article delves into functional programming through the following three sections.

  • Programming paradigm
  • Functional programming
  • Common examples of functional programming

Programming paradigm

Programming paradigm refers to a programming style that describes a programmer’s view of how a program executes. In the world of programming, the same problem can be analyzed and solved from multiple perspectives, and these different solutions correspond to different programming styles.

Common programming paradigms are:

  • Imperative programming
    • Process-oriented programming
      • C
    • Object-oriented programming
      • C++, C#, Java
  • Declarative programming
    • Functional programming
      • Haskell

Imperative programming

Imperative programming is the most widely used style of programming. It is to think from the point of view of the computer. The main idea is to focus on the steps performed by the computer, that is, to tell the computer what to do first and then what to do.

Because there are many steps that need to be controlled, imperative programming generally has the following characteristics:

  • Control statements
    • Loop statements: while, for
    • Conditional branch statements: if else, switch
    • Unconditional branch statements: return, break, continue
  • variable
    • Assignment statement

With these characteristics in mind, let’s look at a case study of imperative programming:

// Need: filter out odd subsets of array

const array = [1.2.3.4.5.6.7.8.9];
// Step 1: Define execution result variables
let reult = [];
// Step 2: control program loop call for (let i = 0; i < array.length; i++) {  // Step 3: Judge the filter criteria  if (array[i] % 2! = =0) {  // Step 4: Add the result  reult.push(array[i]);  } } // Step 5: Get the final result Copy the code

The above code implements the array filter in 5 steps, which is not a problem, but careful students may be confused: the amount of code written in this way is too long, and not semantic, until you read each line of code, you will know exactly what logic is being executed.

Yes, this is typical of imperative programming, but here are some other things:

  • Each step of imperative programming can be defined by the programmer, which can improve the performance of the program by providing finer and tighter control over the code.
  • Each step of imperative programming can record intermediate results for easy debugging of code.
  • Imperative programming requires a large number of flow control statements, and it is easy to cause logic chaos when dealing with multi-thread state synchronization, which usually needs locking to solve.

Declarative programming

Declarative programming is also a style of programming that defines specific rules so that specific functions can be implemented automatically at the bottom of the system. The idea is to tell the computer what to do, but not specify how to do it.

Because of the need to define rules to express meaning, the following characteristics of declarative programming are common:

  • The code is more semantic and easier to understand.
  • Less code.
  • No flow control code is required, such as for, while, if, etc.

Next, let’s filter the above array and refactor it declaratively:

// Filter out the odd subset of the array
const array = [1.2.3.4.5.6.7.8.9];
const reult = array.filter((item) = > item % 2! = =0);
Copy the code

As you can see, declarative programming has no redundant steps, very little code, and is very semantic. When we read filter, we automatically know that we are doing filtering.

Let’s look at another example:

Select * from student where id = 25
select * from students where id=25
Copy the code

In the above code, we just tell the computer, I want to find the student whose ID is 25, and the computer will give us the corresponding data. As for how to find the data, we don’t care, as long as the result is correct.

In addition to the above examples, there are many other examples of declarative programming:

  • HTML is used to declare the content of a web page.
  • CSS is used to declare the appearance of elements in a web page.
  • Regular expressions that declare matching rules.

With these examples in mind, let’s summarize the pros and cons of declarative programming:

  • Declarative programming can greatly reduce the developer’s workload by eliminating the need to write complex operations.
  • The specific operations of declarative programming are unified management of the bottom layer, which can reduce repetitive work.
  • The underlying logic of declarative programming is not controllable and is not suitable for more refined optimizations.

Functional programming

Functional programming is a kind of declarative programming, its main idea is to see the computer operation as a function of the calculation, that is, the program problems into mathematical problems to solve abstract.

In functional programming, we can make full use of mathematical formulas to solve problems. That is, any problem can be solved step by step by using functions (addition, subtraction, multiplication and division) and mathematical laws (commutative laws, associative laws, etc.).

In functional programming, all variables are unique values, just like the algebra x and y in mathematics, which have either not been solved or have been solved to fixed values. Therefore, it is illegal for the increment of x=x+1 to change the algebraic value, which is not in accordance with mathematical logic.

In addition, strictly functional programming does not include control statements such as loops and conditional judgments. If conditional judgments are needed, ternary operators can be used instead.

We mentioned webpack-chain at the beginning of this article. Let’s take a look at it:

// Write the webpack configuration using webpack-chain.
const Config = require('webpack-chain');
const config = new Config();
config.
    .entry('index')
 .add('src/index.js')  .end()  .output  .path('dist')  filename('my-first-webpack.bundle.js'); config.module  .rule('compile')  .test(/\.js$/)  .use('babel')  .loader('babel-loader') module.exports = config; Copy the code

As you can see, Webpack-chain can create and modify WebPack configurations via chained function apis, making it easier to create and modify WebPack configurations. Imagine a WebPack configuration that needs to be used for multiple projects, but each project has slightly different configurations.

If you use Webpack-chain to change the configuration, a function API is done, whereas with imperative programming, you need to step through the entire WebPack configuration file to find the points that need to be changed before you can make changes, which greatly reduces the amount of work.

Features of functional programming

According to wikipedia’s authoritative definition, functional programming has the following characteristics:

  • The function is a first-class citizen
    • Functions, like variables, can be assigned to other variables, passed in as arguments, or returned as values from other functions.
  • Only expressions, not statements:
    • An expression is a pure operation that always returns a value.
    • A statement performs an operation without returning a value.
    • That is, each step in functional programming is pure computation and has a return value.
  • No side effect
    • No results other than operations are produced.
    • The same input always yields the same data.
  • immutability
    • Returns a new value without modifying the variable.
  • Reference transparent
    • Function execution does not depend on external variables, only on input parameters.

The above characteristics are the core of functional programming, and based on these characteristics, there are many application scenarios:

  • Pure function: the same input gets the same output, no side effects.
  • Function combination: Multiple functions that are called in sequence are combined into one large function to simplify operations.
  • Higher-order functions: functions that can process functions, receiving one or more functions as input and one function as output.
  • Closure: function scope nesting, implementation of different scope variables shared.
  • Currization: Conversion of a multi-parameter function into nested single-parameter functions.
  • Partial functions: Cache some arguments and then pass in others as they are used.
  • Lazy evaluation: Multiple operations are defined in advance, but values are not evaluated immediately. In this way, unnecessary evaluation can be avoided and performance can be improved.
  • Recursion: A way of controlling the loop call of a function.
  • Tail-recursion: Optimization to avoid memory overflow caused by multi-level function nesting.
  • Chain calls: Make code more elegant.

These application scenarios exist in a large number of our daily work, let’s go through a few cases to practice.

Common examples of functional programming

Based on the application scenario of functional programming, we will realize several specific cases.

  • Function composition
  • Currie,
  • Partial function
  • Higher-order functions
  • Tail recursion
  • Chain calls

1, function combination, combination of multiple function steps.

function compose(f, g) {
  return function () {
    return f.call(this, g.apply(this.arguments));
  };
}
 function toLocaleUpperCase(str) {  return str.toLocaleUpperCase(); }  function toSigh(str) {  return str + "!"; } // Combine multiple functions into a single function in order of execution to simplify multiple call steps. const composedFn = compose(toSigh, toLocaleUpperCase); console.log("Function combination:", composedFn("msx")); // function combination: MSX! Copy the code

2. Currization, transforming a multi-parameter function into multiple nested single-parameter functions.

/ / curry
function curry(targetfn) {
  var numOfArgs = targetfn.length;
  return function fn(. rest) {
    if (rest.length < numOfArgs) {
 return fn.bind(null. rest); } else {  return targetfn.apply(null, rest);  }  }; } // Add function function add(a, b, c, d) {  return a + b + c + d; } // Convert a multi-argument function to multiple nested single-argument functions console.log("Corrification:", curry(add)(1) (2) (3) (4)); // Currification: 10 Copy the code

3. Partial functions that cache some arguments and then pass in others as they are used.

/ / function
function isTypeX(type) {
  return function (obj) {
    return Object.prototype.toString.call(obj) === `[object ${type}] `;
  };
}  // Cache some of the arguments, and then pass in others as they are used. const isObject = isTypeX("Object"); const isNumber = isTypeX("Number");  console.log("Partial function test:", isObject({ a: 1 }, 123)); // true console.log("Partial function test:", isNumber(1)); // true Copy the code

4, lazy evaluation, predefined multiple operations, but not immediately evaluated, in the need to use the value to evaluate, can avoid unnecessary evaluation, improve performance.

// use LINQ in C# to demonstrate this
Db. Gems [4,15,20,7,3,13,2,20];

var q =
    db.Gems
 .Select(c => c < 10)  .Take(3)  // ToList will not be evaluated unless ToList is called  // In the specific evaluation, the pre-defined methods will be optimized and integrated to produce an optimal solution, then the evaluation will be done.  .ToList(); Copy the code

In the above code, a traditional evaluation would iterate twice, first through the entire array (8 items), filter out items less than 10, and print [4,7,3,2], and second through the array (4 items), and print [4,7,3].

If lazy evaluation is used, all pre-defined operations are judged together, so it only needs to be traversed once. At the same time, judge whether less than 10 and the number of less than 10 is 3. When the fifth term is traversed, [4,7,3] can be output.

Compared with traditional evaluation traversal of 8+4=12 items, using lazy evaluation only requires traversal of 5 items, and the efficiency of the program is naturally improved.

5, higher-order functions, can process functions of the function (receive one or more functions as input, output a function).

// React encapsulates a component as a new component with a default background color.
// styled- Components is the principle
function withBackgroundRedColor (wrapedComponent) {
  return class extends Component {
    render () {
 return (<div style={backgroundColor: 'red} >  <wrapedComponent {. this.props} / >  </div>)  }  } } Copy the code

6. Recursion and tail recursion.

// Ordinary recursion, a way to control function calls loop.
function fibonacci(n) {
  if (n === 0) {
    return 0;
  }
 if (n === 1) {  return 1;  }  return fibonacci(n - 1) + fibonacci(n - 2); } console.log("No tail recursion, resulting in stack overflow", fibonacci(100));  // Tail recursion, avoid multi-level function nesting caused by memory overflow optimization. function fibonacci2(n, result, preValue) {  if (n == 0) {  return result;  }  return fibonacci2(n - 1, preValue, result + preValue); } // result = 0, preValue = 1 console.log("Tail recursion, no stack overflow.", fibonacci2(100.0.1)); Copy the code

6. Chain call

// In loDash, after a method call is complete, you can continue to chain calls to other methods.
var users = [
  { user: "barney".age: 36 },
  { user: "fred".age: 40 },
  { user: "pebbles".age: 1 },
]; var youngest = _.chain(users)  .sortBy("age")  .map(function (o) {  return o.user + " is " + o.age;  })  .head()  .value(); // => 'pebbles is 1' Copy the code

Thinking and summarizing

This paper starts from the programming paradigm, analyzes the positioning of functional programming, further extends the concept of functional programming, and then based on some cases in the work, the actual combat of functional programming application scenarios, I hope everyone can easily understand functional programming.

Finally, if you have any thoughts on this, feel free to leave a comment!

If you think the article is good, welcome to wechat search [front-end log] public number, and share knowledge with me, common progress, thank you!