Abstract
虽然像递归, 但是你要用functional的眼观看待
- 对js做7点限制, 从而体会函数式
- no loops
- no if
- single return
- no side-effects to outside world
- no assignments in functinos
- no arrays
- only 0 or 1 argument
Pure function, 怎么的输入就有怎样的输出,不产生side effect, 如修改外部全局变量。不依赖外部数据, 如根据全局变量的值产生输出。
- 多参数
- 链表
- first, second, …
- head, next
- 数组
- list2array
- array2list
- range
- ⭐ map
多参数逻辑
函数式的上下文在闭包中
加法为例
1
| let add = (a) => (b) => a + b
|
pair
有了pair的概念后就可以递归了
1 2 3 4 5 6
| let pair = (first) => (second) => { return { first: first, second: second, } }
|
取成员
1 2 3 4
| let fst = (pair) => pair.first let snd = (pair) => pair.second fst(pair(1)(2)) snd(pair(1)(2))
|
链表
链表是如何递归的
利用pair做一个手动链表
1
| let list = pair(1)(pair(2)(pair(3)(null)))
|
list2array
有了pair的概念, 迁移到链表上就是: data
, next
。所以可以创建两个辅助函数data
和next
1 2 3 4 5 6 7 8 9 10 11
| let data = (p) => p.first let next = (p) => p.second
let list2array = (node) => { let result = [] while (node !== null) { result.push(data(node)) node = next(node) } return result }
|
array2list
创node, 接node
不够我们这里要从尾到头创建: 递归的尽头是next
1 2 3 4 5 6 7 8
| let array2list = (a) => { let xs = Array.from(a).reverse() let node = null for (let i=0; i<xs.length; i++) { node = pair(xs[i])(node) } return node; }
|
range
给定一个范围自动创建一range的链表
1 2 3 4 5
| let range = (low) => (high) => low > high ? null : pair(low)(range(low+1)(high))
list2array(range(1)(100))
|
map
map(f)(list), 将f作用于list中的所有元素然后返回新list
之所以抽象成list是因为我们想尽可能用函数式的方式遍历
1 2 3 4 5 6 7
| let map = (f) => (list) => { return list === null ? null : pair(f(data(list))) (map(f)(next(list))) }
list2array(map((x) => x*2)(range(1)(10)))
|
总结
- 多参数传递的模式:
- 不管三七二十一, 先把函数参数保存到闭包中再说
- 也就相当于
(arg1, arg2, ...)
变成了(arg1)(arg2)(...)
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 38 39 40 41 42 43 44 45 46
| let pair = (first) => (second) => { return { first: first, second: second, } }
let fst = (pair) => pair.first let snd = (pair) => pair.second
let list = pair(1)(pair(2)(pair(3)(null)))
let data = (p) => p.first let next = (p) => p.second
let list2array = (node) => { let result = [] while (node !== null) { result.push(data(node)) node = next(node) } return result }
let array2list = (a) => { let xs = Array.from(a).reverse() let node = null for (let i=0; i<xs.length; i++) { node = pair(xs[i])(node) } return node; }
let range = (low) => (high) => low > high ? null : pair(low)(range(low+1)(high))
list2array(range(1)(100))
let map = (f) => (list) => { return list == null ? null : pair(f(data(list))) (map(f)(next(list))) }
list2array(map((x) => x*2)(range(1)(10)))
|