Interviewer: Hello, have you ever used functional programming? Me: Functional? Don’t? Interviewer: Do you know anything about that? Me: Uh… B: No. Does your company mainly use functional programming? Interviewer: Well, not really, but I just want to ask

It’s the interview season again, and many small partners will be asked repeatedly by the interviewer. They will build a rocket during the interview and screw it in. But they still have to build a rocket if they want to be hired smoothly.

Recently, I wrote some knowledge points related to the interview irregularly to encourage everyone’s interview.

In this article we talk about functional programming.

Functional programming is a programming paradigm, and object-oriented, process-oriented is a programming methodology, is simply how to design our program structure.

The main idea of a functional is to write an operation as a series of function calls, as we do for procedures

f(msg){
 / / separated MSG./ / stitching MSG.// Other processing. }Copy the code

The function is going to look like this

a(msg){.../ / separated MSG}
b(msg){.../ / stitching MSG}
c(msg){...// other processing}
f(msg) = a(msg).b(msg).c(msg)
Copy the code

Is equivalent to the original one big function apart into separate small function, and then through the chain calls, the independent function together, has reached the output results are consistent with the original big function, somewhat similar to the pipeline, or lines, in a process to deal with end, passed on to the next working procedure, the final output of finished product.

In functional programming, a function must meet a basic condition: the function must have no side effects, cannot directly or indirectly modify variables other than itself, and is merely an act of data transformation. Piece of grass in the past, neither touch flowers nor grass.

Functional programming has two basic operations: composition and keriification.

In the previous article, we introduced the function Coriolization in detail. Please introduce coriolization functions in plain English. We will move on to another basic operation – composition

What is a composer

Function composition, which is called compose, means that a value must pass through multiple functions to become another value. Combining these functions into a single function is the composition of functions, for example

var name = 'xiaoli'name = a(name){... } name = b(name){... } name = c(name){... }console.log(name)
Copy the code

Name goes through three functions to finally output the value we need, so after the function composition, it becomes the following

var fn = compose(a,b,c)
console.log(fn(name))
Copy the code

Here is a picture of Teacher Ruan Yifeng

Function combination is very easy to understand, the standard function combination also needs to meet the associative law, in reference to teacher Ruan Yifeng’s figure

Means to compose (a, b) the generated function must also be a pure function, callers to the generated function is transparent, the caller only concerned with the realization of a and b.

Compose implementation

I’d like to recommend redux, the best at functional programming, and it’s the same guys who put functional programming on the front end. Let’s look at the code

// https://github.com/reduxjs/redux/blob/master/src/compose.js
/** * Composes single-argument functions from right to left. The rightmost * function can take multiple arguments as it provides the signature for * the resulting composite function. * * @param {... Function} funcs The functions to compose. * @returns {Function} A function obtained by composing the argument functions * from right to left. For example, compose(f, g, h) is identical to doing * (... args) => f(g(h(... args))). */

export default function compose(. funcs) {
  if (funcs.length === 0) {
    return arg= > arg
  }

  if (funcs.length === 1) {
    return funcs[0]}return funcs.reduce((a, b) = >(... args) => a(b(... args))) }Copy the code

Isn’t it refined? Array.reduce method well, clever implementation of function nested reference.

How to implement lodash.js before looking at other libraries

/** * Composes a function that returns the result of invoking the given functions * with the `this` binding of the created function, Where each successive * invocation is supplied the return value of the previous. * * @since 3.0.0 * @category Util * @param {Function[]} [funcs] The functions to invoke. * @returns {Function} Returns the new composite function. * @see flowRight * @example * * function square(n) { * return n * n * } * * const addSquare = flow([add, square]) * addSquare(1, 2) * // => 9 */
function flow(funcs) {
  const length = funcs ? funcs.length : 0
  let index = length
  while (index--) {
    if (typeoffuncs[index] ! ='function') {
      throw new TypeError('Expected a function')}}return function(. args) {
    let index = 0
    let result = length ? funcs[index].apply(this, args) : args[0]
    while (++index < length) {
      result = funcs[index].call(this, result)
    }
    return result
  }
}
Copy the code

Loadsh looks a little more complicated, but it’s more compatible because some of the older browsers don’t support Reduce

For example, ramda.js is a library for composing functions, which are composed by default. For example, ramda.js is a library for composing functions. For example, ramda.js is a library for composing functions

// compose.js
import pipe from './pipe';
import reverse from './reverse';
/** * @func * @category Function * @sig ((y -> z), (x -> y), ... , (o -> p), ((a, b, ... , n) -> o)) -> ((a, b, ... , n) -> z) * @param {... Function} ... functions The functions to compose * @return {Function} * @see R.pipe * @symb R.compose(f, g, h)(a, b) = f(g(h(a, b))) */
export default function compose() {
  if (arguments.length === 0) {
    throw new Error('compose requires at least one argument');
  }
  return pipe.apply(this, reverse(arguments));
}

// pipe.js
import _pipe from './internal/_pipe';
import reduce from './reduce';
export default function pipe() {
  if (arguments.length === 0) {
    throw new Error('pipe requires at least one argument');
  }
  return _arity(
    arguments[0].length,
    reduce(_pipe, arguments[0], tail(arguments))); }// There are several levels of encapsulation
Copy the code

Ramda implements Reduce itself, so compatibility is OK.

For compose, the order in which the functions are executed is left to right or right to left.

Compose the application

There are many use scenarios of function combination. For common data processing, different results can be input as long as the function factors are modified, and the original process does not need to be modified. Let me write a simple chestnut

// Because I prefer to execute from left to right, the order in Reduce is reversed slightly
function compose(. funcs) {
    if (funcs.length === 0) {
        return arg= > arg
    }

    if (funcs.length === 1) {
        return funcs[0]}return funcs.reduce((a, b) = > {
      return  (. args) = >b(a(... args))// Execute from left to right})}function fristName(name){
    return name.split(' ') [0]}function upperCase(string){
    return string.toUpperCase()
}
function reverse(string){
    return string.split(' ').reverse().join(' ')}console.log(compose(fristName,upperCase,reverse)('xiao li')) // OAIX
Copy the code

Compose is very handy to use, and I’m sure you can write a lot of interesting code based on Compose.

Let’s take a look at how the awesome KOA2 framework, which is composed, implements the Onion model, which I think is very clever and is the essence of KOA

// https://github.com/koajs/koa/blob/master/lib/application.js
 /** * Return a request handler callback * for node's native http server. * * @return {Function} * @api public */

  callback() {
    const fn = compose(this.middleware);

    if (!this.listenerCount('error')) this.on('error'.this.onerror);

    const handleRequest = (req, res) = > {
      const ctx = this.createContext(req, res);
      return this.handleRequest(ctx, fn);
    };

    return handleRequest;
  }
// https://github.com/koajs/compose/blob/master/index.js
/** * Compose `middleware` returning * a fully valid middleware comprised * of all those which are passed. * * @param {Array} middleware * @return {Function} * @api public */

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array! ')
  for (const fn of middleware) {
    if (typeoffn ! = ='function') throw new TypeError('Middleware must be composed of functions! ')}/** * @param {Object} context * @return {Promise} * @api public */

  return function (context, next) {
    // last called middleware #
    let index = - 1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if(! fn)return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}
Copy the code

summary

Using compose with Curry makes the function very flexible, but there are some requirements for writing the function: how to avoid side effects, how to design the input and output of the function, how to design the bounds of the function, and so on.

Using functional programming in some scenarios not only makes your code more extensible, but it also makes your code look superior.

Speaking of here, if in the interview when the above mentioned point and chestnut roughly speak out, the interview of this pass that absolutely steady.

Refer to the article

www.ruanyifeng.com/blog/2017/0…