# 基于JavaScript的一些函数式编程概念讲解

## Functional Programming Jargon:函数式编程术语解释

### Arity:参数数目

const sum = (a, b) => a + b;

const arity = sum.length;
console.log(arity);
// => 2
// The arity of sum is 2

### Higher-Order Functions (HOF):高等函数

const filter = (pred, xs) => {
const result = [];
for (var idx = 0; idx < xs.length; idx += 1) {
if (pred(xs[idx])) {
result.push(xs[idx]);
}
}
return result;
};
const is = type => x => Object(x) instanceof type;
filter(is(Number), [0, '1', 2, null]); //=> [0, 2]

### Partial Application:局部封装

let sum = (a, b) => a + b;

// partially applying `a` to `40`
let partial = sum.bind(null, 40);

// Invoking it with `b`
partial(2); //=> 42

### Currying

let sum = (a, b) => a + b;

let curriedSum = (a) => (b) => a + b;

curriedSum(40)(2) // 42.

### Composition:组合

const compose = (f, g) => a => f(g(a)) // Definition
const floorAndToString = compose((val)=> val.toString(), Math.floor) //Usage
floorAndToString(121.212121) // "121"

### Purity:纯函数

let greet = "yo";

greet.toUpperCase(); // YO;

greet // yo;

As opposed to:

let numbers = [1, 2, 3];

numbers.splice(0); // [1, 2, 3]

numbers // []

### Side effects:副作用

console.log("IO is a side effect!");

### Idempotency:幂等性

f(f(x)) = f(x)

Math.abs(Math.abs(10))

### Point-Free Style

// Given
let map = fn => list => list.map(fn);
let add = (a, b) => a + b;

// Then

// Not points-free - `numbers` is an explicit parameter
let incrementAll = (numbers) => map(add(1))(numbers);

// Points-free - The list is an implicit parameter

incrementAll明确规定了参数numbers, 而incrementAll2是对于参数的封装，并没有显性说明numbers参数，因此它可以被称为Points Free。一般来说，Points-free的函数都不会用常见的function或者=>关键字来定义。

### Value:值

5
Object.freeze({name: 'John', age: 30}) // The `freeze` function enforces immutability.
(a) => a

### Constant:常量

const five = 5
const john = {name: 'John', age: 30}

john.age + five === ({name: 'John', age: 30}).age + (5)

### Functor

Functor即指那些可以引用map函数的对象，JavaScript中最简单的函数就是Array

[2,3,4].map( n => n * 2 ); // [4,6,8]

Let func be an object implementing a map function, and f, g be arbitrary functions, then func is said to be a functor if the map function adheres to the following rules:

func.map(x => x) == func

func.map(x => f(g(x))) == func.map(g).map(f)

[1, 2, 3].map(x => x); // = [1, 2, 3]

let f = x => x + 1;
let g = x => x * 2;

[1, 2, 3].map(x => f(g(x))); // = [3, 5, 7]
[1, 2, 3].map(g).map(f);     // = [3, 5, 7]

### Pointed Functor

Pointed Functor在Array中的实现为：

Array.prototype.of = (v) => [v];

[].of(1) // [1]

### Lift

Lift很类似于map，不过它可以用于多个Functors：

lift(n => n * 2)([2,3,4]); // [4,6,8]

lift((a, b)  => a * b)([1, 2], [3]); // [3, 6]

### Referential Transparency:透明引用

let greet = () => "Hello World!";

### Lazy evaluation:懒计算

Lazy evaluation 即是所谓的只有在需要某个值的时候才进行计算的机制。在函数式语言中，这个机制就允许对于那些近乎无限的列表进行操作。

let rand = function*() {
while(1<2) {
yield Math.random();
}
}
let randIter = rand();
randIter.next(); // Each exectuion gives a random value, expression is evaluated on need.

### Monoid:独异点

1 + 1; // 2

1 + 0; // 1

1 + (2 + 3) == (1 + 2) + 3; // true

[1, 2].concat([3, 4]); // [1, 2, 3, 4]

[1, 2].concat([]); // [1, 2]

['cat,dog','fish,bird'].chain(a => a.split(',')) // ['cat','dog','fish','bird']

//Contrast to map
['cat,dog','fish,bird'].map(a => a.split(',')) // [['cat','dog'], ['fish','bird']]

You may also see of and chain referred to as return and bind (not be confused with the JS keyword/function...) in languages which provide Monad-like constructs as part of their standard library (e.g. Haskell, F#), on Wikipedia and in other literature. It's also important to note that return and bind are not part of the Fantasy Land spec and are mentioned here only for the sake of people interested in learning more about Monads.

let CoIdentity = v => ({
val: v,
extract: this.v,
extend: f => CoIdentity(f(this))
})

Extract 可以将值从Functor中吐出来：

CoIdentity(1).extract() // 1

CoIdentity(1).extend(co => co.extract() + 1) // CoIdentity(2)

### Applicative(可适用的) Functor

[(a)=> a + 1].ap([1]) // [2]

### Isomorphism:同态转换

// Providing functions to convert in both directions makes them isomorphic.
const pairToCoords = (pair) => ({x: pair[0], y: pair[1]})

const coordsToPair = (coords) => [coords.x, coords.y]

coordsToPair(pairToCoords([1, 2])) // [1, 2]

pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2}

### Setoid

Array.prototype.equals = arr => {
var len = this.length
if (len != arr.length) {
return false
}
for (var i = 0; i < len; i++) {
if (this[i] !== arr[i]) {
return false
}
}
return true
}

[1, 2].equals([1, 2]) // true
[1, 2].equals([0]) // false

### Semigroup:半群

[1].concat([2]) // [1, 2]

### Foldable:可折叠

let sum = list => list.reduce((acc, val) => acc + val, 0);
sum([1, 2, 3]) // 6

### Type Signatures:类型签名

// functionName :: firstArgType -> secondArgType -> returnType

// add :: Number -> Number -> Number
let add = x => y => x + y

// increment :: Number -> Number
let increment = x => x + 1

// call :: (a -> b) -> a -> b
let call = f => x => f(x)

// map :: (a -> b) -> [a] -> [b]
let map = f => list =>  list.map(f)

4989 人关注
359 篇文章