基本概念 chain 就是 compose(join,map)
functor: 算子 A functor is a container of type a that, when subjected to a function that maps from a→b, yields a container of type b.我们的 map 函数就是一个算子。
container 一个容器可以放任何东西,甚至是另一个容器.比如我们的数组就是这种容器。
map: 是传入一个 function,把 function 应用到 container 里的值,然后返回这个 container
1
2
3
Container . prototype . map = f => Container . of ( f ( this . $value ))
// 数组的角度
[ 1 , 2 , 3 ]. map ( x => x + 1 )
Maybe 是一种值可能是 null/undefined 的容器,如果是 null/undefined 时会做特殊处理,比如 map 时就不执行 f,直接返回自己.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Maybe {
static of ( x ) {
return new Maybe ( x );
}
isNothing = this . $value === null || this . $value === undefined ;
constructor ( x ) {
this . $value = x ;
}
map ( fn ) {
return this . isNothing ? this : Maybe . of ( fn ( this . $value ));
}
// array
[ 1 , null , undefined ]. map ( x => x + 1 ) // => [2, null, undefined]
Either 比 Maybe 更 general 的容器,它是两种可能的容器中和一种,左和右(默认右值)。这两个容器有各自的处理逻辑,主要用于做错误处理。Either(string, number)表示这个容器或者是 Left(string)或者是 Right(number).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static of ( x ) {
return new Right ( x );
}
constructor ( x ) {
this . $value = x ;
}
}
class Left extends Either {
map ( f ) {
return this ;
}
}
class Right extends Either {
map ( f ) {
return Either . of ( f ( this . $value ));
}
}
IO IO 是一个里面放了一个函数的容器,这个函数不用是纯函数,IO 是用来封装副作用的。
1
2
3
4
5
6
7
8
9
10
11
12
13
class IO {
static of ( x ) {
return new IO (() => x );
}
constructor ( fn ) {
this . $value = fn ;
}
map ( fn ) {
return new IO ( compose ( fn , this . $value ));
}
}
Task Task 是一种 IO,它内部的 func(又叫 fork)有特定的样子(reject, resolve) => {…}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Task {
constructor ( fork ) {
this . fork = fork ;
}
static of ( x ) {
return new Task (( _ , resolve ) => resolve ( x ));
}
static rejected ( x ) {
return new Task (( reject , _ ) => reject ( x ));
}
ap ( f ) {
return this . chain ( fn => f . map ( fn ));
}
chain ( fn ) {
return new Task (( reject , resolve ) => this . fork ( reject , x => fn ( x ). fork ( reject , resolve )));
}
inspect () { // eslint-disable-line class-methods-use-this
return 'Task(?)' ;
}
getType () { // eslint-disable-line class-methods-use-this
return '(Task ? ?)' ;
}
join () {
return this . chain ( x => x );
}
map ( fn ) {
return new Task (( reject , resolve ) => this . fork ( reject , compose ( resolve , fn )));
}
}
理论 下面这些是等价的:
1
2
map ( id ) === id
compose ( map ( f ), map ( g )) === map ( compose ( f , g ))
算子互换 2 个 functor 如果可以互换,我们就说他们是 Isomorphic 。因为互换中他们没有信息丢失。
如 Promise 和 Task 就是 Isomorphic
1
2
3
4
5
// promiseToTask :: Promise a b -> Task a b
const promiseToTask = x => new Task (( reject , resolve ) => x . then ( resolve ). catch ( reject ));
// taskToPromise :: Task a b -> Promise a b
const taskToPromise = x => new Promise (( resolve , reject ) => x . fork ( reject , resolve ));
Natural transformations 是在算子上的函数。
An introduction for FP to Js User pure function: functions same input and same output replace the value and function impure world monad
interpreter pattern
Algebraic Data Type & Monads & Functors Algebraic Data Type: Either, Reader, Writer, IO, Option
Monads: has map and flatMap
Functor: functions to convert a value from one strategy to another strategy
plethora demystify honed