# shfshanyue/fp-jargon-zh

Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.

# 函数式编程术语

## Arity

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

const arity = sum.length
console.log(arity)        // 2```

## 高阶函数 (Higher-Order Function / HOF)

```const filter = (predicate, xs) => xs.filter(predicate)

const is = (type) => (x) => Object(x) instanceof type

filter(is(Number), [0, '1', 2, null]) // 0, 2```

## 偏函数 (Partial Function)

```// 创建偏函数，固定一些参数
const partical = (f, ...args) =>
// 返回一个带有剩余参数的函数
(...moreArgs) =>
// 调用原始函数
f(...args, ...moreArgs)

const add3 = (a, b, c) => a + b + c

// (...args) => add3(2, 3, ...args)
// (c) => 2 + 3 + c
const fivePlus = partical(add3, 2, 3)

fivePlus(4)  // 9```

`const add1More = add3.bind(null, 2, 3)`

## 柯里化 (Currying)

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

const curriedSum = (a) => (b) => a + b

curriedSum(3)(4)         // 7

## 自动柯里化 (Auto Currying)

`lodash``understore``ramda``curry` 函数可以自动完成柯里化。

```const add = (x, y) => x + y

curriedAdd(1)      // (y) => 1 + y```

## 函数组合 (Function Composing)

```const compose = (f, g) => (a) => f(g(a))    // 定义
const floorAndToString = compose((val) => val.toString(), Math.floor) // 使用
floorAndToString(12.12)   // '12'```

## Continuation

```const printAsString = (num) => console.log(`Given \${num}`)

const addOneAndContinue = (num, cc) => {
const result = num + 1
cc(result)
}

Continuation 在异步编程中很常见，比如当程序需要接收到数据才能够继续执行。请求的响应通常作为代码的剩余执行部分，一旦接收到数据，对数据的处理被作为 Continuation。

```const continueProgramWith = (data) => {
// 继续执行程序
}

if (err) {
// 错误处理
return
}
continueProgramWith(response)
})```

## 纯函数 (Purity)

```const greet = (name) => `hello, \${name}`

greet('world')```

```window.name = 'Brianne'

const greet = () => `Hi, \${window.name}`

greet() // "Hi, Brianne"```

```let greeting

const greet = (name) => {
greeting = `Hi, \${name}`
}

greet('Brianne')
greeting // "Hi, Brianne"```

## 副作用 (Side effects)

`const differentEveryTime = new Date()`
`console.log('IO is a side effect!')`

## 幂等性 (Idempotent)

`f(f(x)) ≍ f(x)`
`Math.abs(Math.abs(10))`
`sort(sort(sort([2, 1])))`

## Point-Free 风格 (Point-Free Style)

```const map = (fn) => (list) => list.map(fn)
const add = (a) => (b) => a + b

# Points-Free   list 是显式参数
const incrementAll = (numbers) => map(add(1))(numbers)

# Points-Free   list 是隐式参数

`incrementAll` 识别并且使用了 `numbers` 参数，因此它不是 Point-Free 风格的。 `incrementAll2` 连接函数与值，并不提及它所使用的参数，因为它是 Point-Free 风格的。

Point-Free 风格的函数就像平常的赋值，不使用 `function` 或者 `=>`

## 谓词 (Predicate)

```const predicate = (a) => a > 2

;[1, 2, 3, 4].filter(predicate)```

## 契约 (Contracts)

```const contract = (input) => {
if (typeof input === 'number') return true
throw new Error('Contract Violated: expected int -> int')
}

const addOne = (num) => contract(num) && num + 1

TODO

## 范畴 (Category)

1. 必有一个 identity 态射，使得 map 一个对象是它自身。`a` 是范畴里的一个对象时，必有一个函数使 `a -> a`
2. 态射必是可组合的。`a``b``c` 是范畴里的对象，`f` 是态射 `a -> b``g``b -> c` 态射。`g(f(x))` 一定与 `(g ● f)(x)` 是等价的。
3. 组合满足结合律。`f ● (g ● h)``(f ● g) ● h` 是等价的。

## 值 (Value)

```5
Object.freeze({name: 'John', age: 30})
;(a) => a
;[1]
undefined```

## 常量 (Constant)

```const five = 5
const john = Object.freeze({name: 'John', age: 30})```

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

## 函子 (Functor)

### 一致性 (Preserves identity)

`object.map(x => x) ≍ object`

### 组合性 (Composable)

`object.map(compose(f, g)) ≍ object.map(g).map(f)  // f, g 为任意函数`

```const f = x => x + 1
const g = x => x * 2

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

### Pointed Functor

ES2015 添加了 `Array.of`，使 Array 成为了 Pointed Functor。

`Array.of(1)`

TODO

## 引用透明性 (Referential Transparency)

`const greet = () => 'hello, world.'`

TODO

## 匿名函数 (Lambda)

```;(function (a) {
return a + 1
})

;(a) => a + 1```

`[1, 2].map((a) => a + 1)`

`const add1 = (a) => a + 1`

## 惰性求值 (Lazy evaluation)

```const rand = function* () {
while (true) {
yield Math.random()
}
}

const randIter = rand()
randIter.next()```

## Monoid

`1 + 1   // 2`

`1 + 0   // 1`

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

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

`identity` 值为空数组

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

identity 与 compose 函数能够组成 monoid

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

foo 是只带一个参数的任意函数

`compose(foo, identity) ≍ compose(identity, foo) ≍ foo`

```Array.prototype.chain = function (f) {
return this.reduce((acc, it) => acc.concat(f(it)), [])
}

// ['cat', 'dog', 'fish', 'bird']
;Array.of('cat,dog', 'fish,bird').chain(s => s.split(','))

// [['cat', 'dog'], ['fish', 'bird']]
;Array.of('cat,dog', 'fish,bird').map(s => s.split(','))```

```const CoIdentity = (v) => ({
val: v,
extract () {
return this.val
},
extend (f) {
return CoIdentity(f(this))
}
})```
```CoIdentity(1).extract()
CoIdentity(1).extend(x => x.extract() + 1)   # CoIdentity(2)```

## Applicative Functor

```// 实现
Array.prototype.ap = function (xs) {
return this.reduce((acc, f) => acc.concat(xs.map(f)), [])
}

// 示例
;[(a) => a + 1].ap([1]) // [2]```

```// Arrays that you want to combine
const arg1 = [1, 3]
const arg2 = [4, 5]

// combining function - must be curried for this to work
const add = (x) => (y) => x + y

const partiallyAppliedAdds = [add].ap(arg1) // [(y) => 1 + y, (y) => 3 + y]```

`partiallyAppliedAdds.ap(arg2) // [5, 6, 7, 8]`

## 态射 (Morphism)

### 自同态 (Endomorphism)

```// uppercase :: String -> String
const uppercase = (str) => str.toUpperCase()

// decrement :: Number -> Number
const decrement = (x) => x - 1```

### 同构 (Isomorphism)

```// 提供函数在两种类型间互相转换
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 = function (arr) {
const len = this.length
if (len !== arr.length) {
return false
}
for (let i = 0; i < len; i++) {
if (this[i] !== arr[i]) {
return false
}
}
return true
}

;[1, 2].equals([1, 2])   // true
;[1, 2].equals([3, 4])   // false```

## 半群 (Semigroup)

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

## Foldable

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

TODO

## 类型签名 (Type Signatures)

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

// add :: Number -> Number -> Number
const add = (x) => (y) => x + y

// increment :: Number -> Number
const increment = (x) => x + 1```

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

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

## 联合类型 (Union Type)

js 没有静态类型，我们假设一个数据类型是 `NumOrString` 用来对 `Number``String` 两种类型求和。

js 中可以对数值或字符串使用 `+` 操作符，因此我们可以使用这个新类型去描述输入输出。

```// add :: (NumOrString, NumOrString) -> NumOrString
const add = (a, b) => a + b

add(1, 2) // Returns number 3
add('Foo', 2) // Returns string "Foo2"
add('Foo', 'Bar') // Returns string "FooBar"```

## Product type

```// point :: (Number, Number) -> {x: Number, y: Number}
const point = (x, y) => ({x: x, y: y})```

## Option

Option 是一种联合类型，它有两种情况，`Some` 或者 `None`

```// 定义
const Some = (v) => ({
val: v,
map (f) {
return Some(f(this.val))
},
chain (f) {
return f(this.val)
}
})

const None = () => ({
map (f) {
return this
},
chain (f) {
return this
}
})

// maybeProp :: (String, {a}) -> Option a
const maybeProp = (key, obj) => typeof obj[key] === 'undefined' ? None() : Some(obj[key])```

```// getItem :: Cart -> Option CartItem
const getItem = (cart) => maybeProp('item', cart)

// getPrice :: Item -> Option Number
const getPrice = (item) => maybeProp('price', item)

// getNestedPrice :: cart -> Option a
const getNestedPrice = (cart) => getItem(obj).chain(getPrice)

getNestedPrice({}) // None()
getNestedPrice({item: {foo: 1}}) // None()
getNestedPrice({item: {price: 9.99}}) // Some(9.99)```