Some necessary concepts

  1. Pure Function

Pure function means that the same input will always get the same output without any significant side effects.

Pure functions are functions in mathematics, and that’s what functional programming is all about.

  1. Side effects

A side effect is a change in the state of the system, or an observable interaction with the external world, during the calculation of the result.

Side effects may include, but are not limited to:

  • Changing a file system
  • Write a record to a database

  • Send an HTTP request

  • Change of state

  • Print to screen/log

  • DOM query

  • Access system state

In summary, any interaction between function and the external environment is a side effect.

  1. Curry

Calling a function with fewer arguments returns a function that takes the remaining arguments. Examples are as follows:

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

const increment = add(1);

const addTen = add(10);

increment(2); / / 3

addTen(2); / / 12
Copy the code

Advantages of functional programming

  1. Deterministic (predictability, data immutable), the same input must get the same outputCopy the code
  2. You can use mathematical lawsCopy the code
// Associative

add(add(x, y), z) === add(x, add(y, z));

// Commutative

add(x, y) === add(y, x);

// Identity

add(x, 0) === x;

// distributive.

multiply(x, add(y,z)) === add(multiply(x, y), multiply(x, z));
Copy the code

Applicable scenarios for functional programming

  • Mutable state
  • Unrestricted Side Effects
  • Unprincipled design

The function is what first-class citizenship means

In JavaScript, functions are first-class citizens, which means that functions, like any other data type, are nothing special — they can be stored in arrays, passed as arguments to functions, assigned to variables, and so on. As a “first-class citizen”, the function has at least the following meanings:

  1. Helps reduce unnecessary refactoringCopy the code
// If the renderPost function changes, the wrapper function must be changed

httpGet('/post/2'.json= > renderPost(json));

// For example, add an err

httpGet('/post/2'.(json, err) = > renderPost(json, err));


If we write it as a first-class citizen function, then there is no need to change it

httpGet('/post/2', renderPost);
Copy the code
  1. Helps increase versatility and reusabilityCopy the code
// For a specific function

const validArticles = articles= >

  articles.filter(article= >article ! = =null&& article ! = =undefined),

// Seemingly infinite versatility and reusability

const compact = xs= > xs.filter(x= >x ! = =null&& x ! = =undefined);
Copy the code
  1. You don't need to use this, but you do need to take care to adapt to external apisCopy the code
const fs = require('fs');

// scary

fs.readFile('freaky_friday.txt', Db.save);

// less so

fs.readFile('freaky_friday.txt', Db.save.bind(Db));
Copy the code

The value of a pure function

  1. cacheableCopy the code
const memoize = (f) = > {

  const cache = {};

  return (. args) = > {

    const argStr = JSON.stringify(args); cache[argStr] = cache[argStr] || f(... args);return cache[argStr];

  };

};


const squareNumber = memoize(x= > x * x);

squareNumber(4); / / 16

squareNumber(4); // 16, returns the cached result of input 4
Copy the code
  1. Portability/Self-documenting (Portable/Self-documenting)Copy the code
// impure
const signUp = (attrs) = > {
  const user = saveUser(attrs);
  welcomeUser(user);
};

// pure
const signUp = (Db, Email, attrs) = > () = > {
  const user = saveUser(Db, attrs);
  welcomeUser(Email, user);
};
Copy the code

Pure functions sign all the variables Db and Email that can change the output, so we know what the function does and what parameters it depends on — providing more information. Portability is a powerful feature of JS. Functions are serialized and transferred over sockets, which means that we can run all the code in a Web worker.

  1. Testable: using characteristics, only inputs and outputs are needed.
  2. (Reasonable) : The same
  3. Parallel Code: Since no shared memory is required, pure functions can be processed in Parallel

Currying

// curry :: ((a, b, ...) -> c) -> a -> b -> ... -> c
function curry(fn) {
  const arity = fn.length;
  return function $curry(. args) {
    if (args.length < arity) {
      return $curry.bind(null. args); }return fn.call(null. args); }; }const match = curry((what, s) = > s.match(what));
const replace = curry((what, replacement, s) = > s.replace(what, replacement));
const filter = curry((f, xs) = > xs.filter(f));
const map = curry((f, xs) = > xs.map(f));
Copy the code

By using the above Currified functions, we can make functional programming simple and without redundancy. We can retain the definition of a mathematical function despite having multiple parameters.

match(/r/g.'hello world'); // [ 'r' ]

const hasLetterR = match(/r/g); // x => x.match(/r/g)
hasLetterR('hello world'); // [ 'r' ]
hasLetterR('just j and s and t etc'); // null
filter(hasLetterR, ['rock and roll'.'smooth jazz']); // ['rock and roll']

const removeStringsWithoutRs = filter(hasLetterR); // xs => xs.filter(x => x.match(/r/g))
removeStringsWithoutRs(['rock and roll'.'smooth jazz'.'drum circle']); // ['rock and roll', 'drum circle']
const noVowels = replace(/[aeiou]/ig); // (r,x) => x.replace(/[aeiou]/ig, r)
const censored = noVowels(The '*'); // x => x.replace(/[aeiou]/ig, '*')
censored('Chocolate Rain'); // 'Ch*c*l*t* R**n'
Copy the code

Composing (Composing)

Composing means to compose functions like “tubes.” The simplest combination example is shown below.

const composes = (f, g) = > x= > f(g(x));
const toUpperCase = x= > x.toUpperCase();
const exclaim = x= > `${x}! `;
const shout = compose(exclaim, toUpperCase);

shout('send in the clowns'); // "SEND IN THE CLOWNS!"
Copy the code

The following is a generic compose function:

const compose = (. fns) = > (. args) = > fns.reduceRight((res, fn) = > [fn.call(null. res)], args)[0];
Copy the code

Because compose is also a pure function, it also satisfies the distributive law:

// It satisfies the distributive property
compose(f, compose(g, h)) === compose(compose(f, g), h);
Copy the code

So it returns the same result regardless of the order in which the parameters are passed, very powerful 👍

const arg = ['jumpkick'.'roundhouse'.'uppercut'];
const lastUpper = compose(toUpperCase, head, reverse);
const loudLastUpper = compose(exclaim, toUpperCase, head, reverse);

lastUpper(arg); // 'UPPERCUT'
loudLastUpper(arg); // 'UPPERCUT! '
Copy the code

Pointfree style

Pointfree means that you do not use the data to be manipulated, but synthesize the process. The following is an example of implementing Pointfree using the PIPE method of the Ramda library, from Ruan Yifeng’s Pointfree Programming Style Guide.

var str = 'Lorem ipsum dolor sit amet consectetur adipiscing elit';
Copy the code

How many characters is the longest string word above? Let’s define some basic operations:

// Separate words with Spaces
var splitBySpace = s= > s.split(' ');

// The length of each word
var getLength = w= > w.length;

// An array of words is converted to an array of dimensions
var getLengthArr = arr= > R.map(getLength, arr);

// Return a larger number
var getBiggerNumber = (a, b) = > a > b ? a : b;

// Return the largest number
var findBiggestNumber = arr= > R.reduce(getBiggerNumber, 0, arr);
Copy the code

Then synthesize the basic operation into a function:

var getLongestWordLength = R.pipe(

  splitBySpace,

  getLengthArr,

  findBiggestNumber

);

getLongestWordLength(str) / / 11
Copy the code

As you can see, the whole operation consists of three steps, each step has a semantic name, very clear. This is the strength of the Pointfree style. Ramda provides a number of off-the-shelf methods that you can use without having to define your own common functions (see the full code).

// Another way of writing the above code

var getLongestWordLength = R.pipe(

  R.split(' '),

  R.map(R.length),

  R.reduce(R.max, 0));Copy the code

Here’s another example from Scott Sauyet”Favoring Curry”. That article is highly recommended for your understanding of Corrification. Below is a snippet of JSON data returned by the server.Now, the requirement is to find all the unfinished tasks for user Scott and rank them in ascending order by expiration date.The code for procedural programming is as follows (seeThe complete code).The code above is not easy to read and the potential for error is high. Now use the Pointfree style rewrite (seeThe complete code).

const getIncompleteTaskSummaries = (name) = > {

  return fetchData()

          .then(R.prop('tasks'))

          .then(R.filter(R.propEq('username', name)))

          .then(R.reject(R.propEq('complete'.true)))

          .then(R.map(R.pick(['id'.'dueDate'.'title'.'priority'])))

          .then(R.sortBy(R.prop('dueDate')))}Copy the code

The code above becomes a lot clearer.

Implementation of common Pointfree pure functions

The implementation below is for basic demonstration purposes only, but for practical development, please refer to Ramda, Lodash, or Folktale.

// curry :: ((a, b, ...) -> c) -> a -> b -> ... -> c

function curry(fn) {

  const arity = fn.length;

  return function $curry(. args) {
    if (args.length < arity) {
      return $curry.bind(null. args); }return fn.call(null. args); }; }// compose :: ((y -> z), (x -> y),  ..., (a -> b)) -> a -> z
const compose = (. fns) = > (. args) = > fns.reduceRight((res, fn) = > [fn.call(null. res)], args)[0];

// forEach :: (a -> ()) -> [a] -> ()
const forEach = curry((fn, xs) = > xs.forEach(fn));

// map :: Functor f => (a -> b) -> f a -> f b

const map = curry((fn, f) = > f.map(fn));

// reduce :: (b -> a -> b) -> b -> [a] -> b

const reduce = curry((fn, zero, xs) = > xs.reduce(fn, zero));

// replace :: RegExp -> String -> String -> String

const replace = curry((re, rpl, str) = > str.replace(re, rpl));

// sortBy :: Ord b => (a -> b) -> [a] -> [a]

const sortBy = curry((fn, xs) = > xs.sort((a, b) = > {

  if (fn(a) === fn(b)) {

    return 0;

  }

  return fn(a) > fn(b) ? 1 : -1;

}));


// prop :: String -> Object -> a

const prop = curry((p, obj) = > obj[p]);
Copy the code

Refer to Pointfree Utilities for more implementations of Pointfree pure functions.

reference

  • Professor Frisby’s Mostly Adequate Guide to Functional Programming
  • Pointfree Javascript

  • Favoring Curry

Welcome to “Byte front-end ByteFE” resume delivery email “[email protected]