Hask 中的类型产品

分类产品

在类别理论中,两个物体 XY 的乘积是另一个具有两个投影的物体 Zπ1:Z→Xπ2:Z→Y ; 使得来自另一个物体的任何其他两个态射通过这些投射唯一地分解。换句话说,如果存在 f 1:W→Xf 2:W→Y ,则存在唯一的态射 g:W→Z ,使得 π1○g = f 1π2○g = f 2

哈斯克的产品

这转化为 Hask Haskell 的类型的类别如下,ZAB 时的产品:

-- if there are two functions
f1 :: W -> A
f2 :: W -> B
-- we can construct a unique function
g  :: W -> Z
-- and we have two projections
p1 :: Z -> A
p2 :: Z -> B
-- such that the other two functions decompose using g
p1 . g == f1
p2 . g == f2

按照上述规律**,两种类型** AB产品类型是 (A,B) 的两种类型的元组,两个投影是 fstsnd。我们可以检查它是否符合上述规则,如果我们有两个函数 f1 :: W -> Af2 :: W -> B 我们可以唯一地分解它们如下:

decompose :: (W -> A) -> (W -> B) -> (W -> (A,B))
decompose f1 f2 = (\x -> (f1 x, f2 x))

我们可以检查分解是否正确:

fst . (decompose f1 f2) = f1
snd . (decompose f1 f2) = f2

同构性的唯一性

(A,B) 作为 AB 的产品的选择并不是唯一的。另一个合乎逻辑的等价选择是:

data Pair a b = Pair a b

而且,我们也可以选择 (B,A) 作为产品,甚至是 (B,A,()),我们也可以按照规则找到类似上面的分解函数:

decompose2 :: (W -> A) -> (W -> B) -> (W -> (B,A,()))
decompose2 f1 f2 = (\x -> (f2 x, f1 x, ()))

这是因为产品不是唯一的,而是同构的独特之AB 的每两个产品不必相等,但它们应该是同构的。举个例子,我们刚刚定义的两个不同的产品 (A,B)(B,A,()) 是同构的:

iso1 :: (A,B) -> (B,A,())
iso1 (x,y) = (y,x,())

iso2 :: (B,A,()) -> (A,B)
iso2 (y,x,()) = (x,y)

分解的唯一性

值得注意的是,分解函数也必须是唯一的。有些类型遵循产品所需的所有规则,但分解并不是唯一的。举个例子,我们可以尝试使用 (A,(B,Bool)) 作为 AB 的产品:fst fst . snd

decompose3 :: (W -> A) -> (W -> B) -> (W -> (A,(B,Bool)))
decompose3 f1 f2 = (\x -> (f1 x, (f2 x, True)))

我们可以检查它是否有效:

fst         . (decompose3 f1 f2) = f1 x
(fst . snd) . (decompose3 f1 f2) = f2 x

但问题是我们可以编写另一个分解,即:

decompose3' :: (W -> A) -> (W -> B) -> (W -> (A,(B,Bool)))
decompose3' f1 f2 = (\x -> (f1 x, (f2 x, False)))

并且,由于分解不是唯一的(A,(B,Bool)) 不是 Hask 中的 AB产物