变型函子
Bifunctor 怎样同时映射两个位置?
- Bifunctor: 拥有两个独立类型参数,可分别变换两个位置;
bimap(f, g):f处理第一个位置,g处理第二个位置;
const Pair = (first, second) => ({
first,
second,
bimap: (f, g) => Pair(f(first), g(second)),
});
Pair("alice", 10).bimap(
(name) => name.toUpperCase(),
(score) => score * 2,
); // Pair('ALICE', 20)
Contravariant Functor 为什么反向变换输入?
- 普通协变函子: 用
A -> B把生产者F<A>变成F<B>; - 逆变函子: 用
B -> A预处理消费者的输入,把F<A>适配为F<B>; - 场景: 谓词、验证器、编码器和排序比较器;
const Predicate = (test) => ({
test,
contramap: (fn) => Predicate((value) => test(fn(value))),
});
const isLong = Predicate((text) => text.length > 5);
const hasLongBio = isLong.contramap((user) => user.bio);
hasLongBio.test({ bio: "Hello World" }); // true
Profunctor 怎样同时改造输入与输出?
- Profunctor
P<A, B>: 消费A并生产B; - 第一个位置逆变: 用
A' -> A预处理输入; - 第二个位置协变: 用
B -> B'后处理输出;
const Profunctor = (run) => ({
run,
promap: (before, after) => Profunctor((value) => after(run(before(value)))),
});
const stringLength = Profunctor((text) => text.length);
const isTrimmedLengthEven = stringLength.promap(
(raw) => raw.trim(),
(length) => length % 2 === 0,
);
isTrimmedLengthEven.run(" code "); // true
三种结构的方向怎样比较?
| 结构 | 变换方向 |
|---|---|
| Bifunctor | 两个位置都协变 |
| Contravariant Functor | 消费者输入位置逆变 |
| Profunctor | 输入逆变、输出协变 |