跳到主要内容

态射与自然变换

态射怎样连接范畴中的对象?​

  • 态射: 同一范畴内对象之间的关系;
  • 函数式编程口径: 函数就是类型对象之间的态射;

同态保留什么结构?​

  • 同态(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

这些态射之间是什么关系?​

态射
├─ 同态:保留指定结构
│ ├─ 自态射:输入输出同类型
│ └─ 同构:存在无损的双向变换
└─ 自然变换:在函子之间保留内部值与映射结构