# compose implementation of functional programming

I was going to study the implementation of compose, but I saw a larger world. Let's take a look at functional programming first, and then learn the implementation of compose.

# 1, Imperative programming VS declarative programming

Common programming paradigms include: imperative programming (process oriented), object-oriented programming (Class), declarative programming, functional programming (a kind of declarative programming), etc.

To achieve (1+2) * 3 / 4, imperative and declarative programming are as follows:

## Imperative programming

It focuses on the specific process of how to do it, and the algorithm implemented to solve a certain problem.

```// , imperative programming is as follows
a = 1 + 2
b = a * 3
c = b / 4
```

A process to solve a problem. You need to look at the code line by line to understand what you want.

## Declarative programming

Focus on goals, what I need.

```divide(multiply(add(1, 2), 3), 4)
```

I need the result after add - > the result after multiply - > the result after divide. While 'how' is left to specific functions, we only focus on what we want.

Declarative programming languages, such as SQL, D3
SQL: what kind of associated data do I want

```SELECT * from dogs
INNER JOIN owners
WHERE dogs.owner_id = owners.id
```

D3: what I want is a circle with x and y centers. The initial value is 0. After half a second, it will be transformed into a radius of 5

```var circles = svg.selectAll('circle')
.data(data)

circles.enter().append('circle')
.attr('cx', function(d) { return d.x })
.attr('cy', function(d) { return d.y })
.attr('r', 0)
.transition().duration(500)
.attr('r', 5)
```

Declarative programming makes us focus more on "what" than "how", and the code looks more readable. It also helps us to solve problems at a higher level. In a suitable scenario, we can apply more declarative programming paradigms.

# 2, Functional programming

Emphasize the one-to-one mapping relationship. For the same input, there will only be the same output. It has the following characteristics:

• Functions are "first-class citizens": the basis of operation is functions, which can be used as input and output parameters for other functions
• Declarative programming: focus on what I want, not how to do it
• Lazy execution: only execute when necessary, with almost no meaningless intermediate variables. Writing functions from beginning to end
• Stateless and data immutable:
Stateless: it does not depend on external states (global variables, this pointer, IO operations, etc.), and the same input is the same output
Immutable data: do not change the original data (do not modify the global and input parameters). If you want to modify an object, you should create a new object to modify it.
• No side effect: the side effect is to manipulate external variables at will, which may lead to bug s caused by shared state, but it is difficult to find the source.
• Pure function: independent of external state (stateless), no side effects (data unchanged). Easy to test and optimize (without mutual influence), easy to cache (one input and only one output)

# 3, Function composition

In functional programming, the two indispensable operations are currying and function combination. Here we mainly talk about function combination.

concept
Combine multiple functions into one to use.

• The first function is multivariate (accepts multiple parameters), and the following functions are all cellular (accepts one parameter)
• Right to left execution sequence
• The execution of all functions is synchronous
```let step1 = (val) => val + 1
let step2 = (val) => val + 2
const steps= [step2, step1]
const composeFuc = compose(...steps)
composeFuc(1) // 4: 1+1=2 -> 2+2=4
```

Simple version understanding:

```const compose = (f, g) => x => f(g(x))
```

Mature version:

```function compose(...fn) {
if (!fn.length) return (v) => v;
if (fn.length === 1) return fn;
return fn.reduce(
(pre, cur) =>
(...args) =>
pre(cur(...args))
);
}
```

analysis:

```function a() {
console.log(1);
}
function b() {
console.log(2);
}
function c() {
console.log(3);
}

compose(a, b, c)

// In order to get this result a(b(c()))

// Execute pre: a, curr: b for the first time
d = (...args) => a(b(...args))

// Execute pre: d, cur: c for the second time. Get a(b(c()))
(...args) => d(c(...args))
```

It is more effective when used with Coriolis.
Coritization implementation:

```function curry(fn, ...args) {
const length = fn.length;
let allArgs = [...args];
const res = (...newArgs) => {
allArgs = [...allArgs, ...newArgs];
if (allArgs.length === length) {
return fn(...allArgs);
} else {
return res;
}
};
return res;
}
```

Use together:

```const split = curry((x, str) => str.split(x));
const join = curry((x, arr) => arr.join(x));
const replaceSpaceWithComma = compose(join(','), split(' ')); // First pass in an x, and then str.
const replaceCommaWithDash = compose(join('-'), split(','));

replaceSpaceWithComma('a b c') // a,b,c
```

Debug of function combination

```const trace = curry((tip, x) => { console.log(tip, x); return x; });
const lastUppder = compose(toUpperCase, head, trace('after reverse'), reverse);
```

Supplement:
Partial function application vs coriolism
Partial function application: fix some parameters and return a function with smaller elements (pass in fewer parameters).

```// Suppose a generic request API
const request = (type, url, options) => ...
// GET request
request('GET', 'http://....')
// POST request
request('POST', 'http://....')

// But after partial call, we can extract the request of a specific type
const get = request('GET');
get('http://', {..})
```