态射与自然变换
态射怎样连接范畴中的对象?
- 态射: 同一范畴内对象之间的关系;
- 函数式编程口径: 函数就是类型对象之间的态射;
同态保留什么结构?
- 同态(Homomorphism): 输入与输出保留所关心的同一种结构性质;
- 示例: 数组与字符串类型不同,但都以
concat和单位元形成幺半群;
const toList = (array) => array.join(", ");
toList([1, 2, 3]); // '1, 2, 3'
自态射为什么最容易组合?
- 自态射(Endomorphism): 输入类型与输出类型相同;
- 因为类型首尾一致,可连续组合而无需转换;
const uppercase = (str) => str.toUpperCase(); // String -> String
const decrement = (x) => x - 1; // Number -> Number
同构怎样证明两个表示没有信息损失?
- 同构(Isomorphism): 两个方向的结构变换都可逆;
- 往返律:
from(to(x)) = x且to(from(y)) = y;
const pairToCoords = ([x, y]) => ({ x, y });
const coordsToPair = ({ x, y }) => [x, y];
coordsToPair(pairToCoords([1, 2])); // [1, 2]
pairToCoords(coordsToPair({ x: 1, y: 2 })); // { x: 1, y: 2 }
自然变换怎样只更换容器?
- 自然变换: 把
F<A>变成G<A>,不检查或改变值A; - 自然性:
nat(fa.map(f)) = nat(fa).map(f);
const listToOption = (xs) => (xs.length ? { value: xs[0], isSome: true } : { isSome: false });
const double = (x) => x * 2;
listToOption([1, 2].map(double)).value === double(listToOption([1, 2]).value); // true
这些态射之间是什么关系?
态射
├─ 同态:保留指定结构
│ ├─ 自态射:输入输出同类型
│ └─ 同构:存在无损的双向变换
└─ 自然变换:在函子之间保留内部值与映射结构