这里记录了 pointfree.co 上, 以下三期视频的 notes:
- Ep #23. The Many Faces of Zip: Part 1
- Ep #24. The Many Faces of Zip: Part 2
- Ep #25. The Many Faces of Zip: Part 3
zip的本质: 一个映射
最常见的 zip
考虑显然存在这样的映射A, B -> (A, B)
. 那么对任意一个包含T
的结构Struct<T>
, 我们一定可以给出映射g: Struct<A> , Struct<B> -> Struct<(A, B)>
. 这样的映射就是zip
.
这里的Struct
可以是 Swift 中的许多有意义的结构, 比如:
- Optional
- Array
- function
- callback function
- 任意有"包含"关系的 plain structure
例如, 针对Optional
, 我们可以实现
1 | func zip<A, B>(_ lhs: Optional<A>, _ rhs: Optional<B>) -> Optional<(A, B)> { |
又例如, 针对 function: () -> T
, 我们可以实现
1 | typealias Function<T> = () -> T |
Swift 提供的 zip
在标准库中zip(Sequence<A>, Sequence<B>) -> Sequence<(A, B)>
就是一个通用的例子. (实为伪代码, 实际上 return type 是一个 concrete type)
第一方许多 framework 也提供了 zip. 例如: Combine 给许多遵循Publisher
的 concrete type, 增加了成员方法, 结构为Publisher<A>.zip(Publisher<B>) -> Publisher<(A, B)>
. (实为伪代码, 方法所在的类型和 return type 都是 concrete type, 泛型参数也稍有不同)
通用的二元 zip
给定一个映射f: (A, B) -> C
, 对任意一个包含T
的结构Struct<T>
, 我们一定可以给出映射g: (Struct<A> , Struct<B>) -> Struct<C>
.
例如, 针对 callback function: ((T) -> Void) -> Void
的例子:
1 | // 给定 f |
- 有时候称是 zip, 上文常见 zip 是这种定义下的一个特例, 即指定了
f(A, B) = (A, B)
. - 有时候称
f->g
是 zip, 这个 zip 更高阶, 并且可以由Struct
的结构唯一确定.
例如, 高阶形式的Array
的 zip 可以这么实现:
1 | func zip<A, B, C>(with f: @escaping (A, B) -> C) -> ([A], [B]) -> [C] { |
多元 zip
在二元 zip 的基础上, 把 f 的输入个数增加即可. 最常见的多元 zip 也是基于 tuple的, 即f: (T1, T2, T3...) -> (T1, T2, T3...)
.
当然参照二元的例子, 也有高阶的多元 zip.
zip
和map
的联系
map
可以看成是通用的多元 zip 的一个特例. 固定 f 中的输入个数为1个即可得到 map 的定义.
给定一个映射f: A -> B
, 对任意一个包含T
的结构Struct<T>
, 我们一定可以给出映射g: Struct<A> -> Struct<B>
.