Hask甚至是一个类别吗?
Is Hask even a category?
https://wiki.haskell.org/Hask:
Consider:
undef1 = undefined :: a -> b
undef2 = \_ -> undefined
Note that these are not the same value:
seq undef1 () = undefined
seq undef2 () = ()
This might be a problem, because undef1 . id = undef2
. In order to make Hask a category, we define two functions f
and g
as the same morphism if f x = g x
for all x
. Thus undef1
and undef2
are different values, but the same morphism in Hask.
这是什么意思或我如何检查:
undef1
和undef2
是不同的值,但是同一个态射?
在 Haskell 中,我们认为每个表达式都可以计算为特定的 "value",我们可能有兴趣确定两个表达式是否具有 "same" 值。
非正式地,我们知道可以直接比较某些值(例如 Integer
类型的值 2
和 3
)。其他值,如 sqrt
和 id
类型 Double -> Double
可以进行比较,正如@pigworker 指出的那样,通过构造一个表达式 "witnesses" 直接比较值的差异:
sqrt 4 = 2
id 4 = 4
这里,我们可以得出结论,sqrt
和id
是不同的值。如果没有这样的见证人,那么价值是一样的。
如果我们查看 undef1
和 undef2
到 () -> ()
类型的单态特化:
undef1, undef2 :: () -> ()
undef1 = undefined
undef2 = \_ -> undefined
我们如何判断这些值是否不同?
好吧,我们需要找到一个可以证明差异的表达式,上面已经给出了一个。两个表达式:
> seq undef1 ()
*** Exception: Prelude.undefined
> seq undef2 ()
()
>
根据 GHCi,具有不同的值。我们也可以直接展示这一点,使用我们对 Haskell 语义的理解:
seq undef1 ()
-- use defn of undef1
= seq undefined ()
-- seq semantics: WHNF of undefined is _|_, so value is _|_
= _|_
seq undef2 ()
-- use defn of undef2
= seq (\_ -> undefined) ()
-- seq semantics: (\_ -> undefined) is already in WHNF and is not _|_,
-- so value is second arg ()
= ()
所以,问题是什么?好吧,当将 Hask 视为一个 类别 时,对象是类型而态射是(单态)函数,我们隐含地需要一个概念 identity/equality 用于对象和态射。
对象 identity/equality 很简单:两个对象(单态 Haskell 类型)当且仅当它们是同一类型时才相等。态射 identity/equality 更难。因为 Hask 中的态射是 Haskell 值(单态函数类型),所以很容易将态射相等定义为与值相等相同,如上所述。
如果我们使用这个定义,那么undef1
和undef2
将是不同的态射,因为我们已经证明它们是不同的Haskell以上值。
但是,如果我们比较 undef1 . id
和 undef2
,我们会发现它们具有 相同的 值。也就是说,没有任何表情可以看出它们之间的区别。证明这有点困难,但请参阅下文。
无论如何,我们现在的 Hask 范畴理论存在矛盾。因为 id
是 Hask 中的(多态族)恒等态射,我们必须有:
undef1
= undef1 . id -- because `id` is identity
= undef2 -- same value
所以我们同时有 undef1 /= undef2
因为上面的见证,但是 undef1 = undef2
由前面的论点。
避免这种矛盾的唯一方法是放弃将 Hask 中的态射相等定义为基础 Haskell 值相等的想法。
已提供的 Hask 中态射相等的另一个替代定义是两个态射 f
和 g
相等的较弱定义,如果和仅当它们满足所有值 x
(包括 _|_
)的 f x = g x
时。请注意,这里仍然存在歧义。如果 f x
和 g x
是 它们自己 Haskell 函数等态射,f x = g x
是否意味着 态射相等 f x
和 g x
或 Haskell 值 f x
和 g x
相等?让我们暂时忽略这个问题。
根据这个替代定义,undef1
和 undef2
是 等同的态射,因为我们可以显示 undef1 x = undef2 x
所有可能的值 x
类型 ()
(即 ()
和 _|_
)。也就是说,应用于 ()
,他们给出:
undef1 ()
-- defn of undef1
= undefined ()
-- application of an undefined function
= _|_
undef2 ()
-- defn of undef2
= (\_ -> undefined) ()
-- application of a lambda
= undefined
-- semantics of undefined
= _|_
并应用于 _|_
他们给出:
undef1 _|_
-- defn of undef1
= undefined _|_
-- application of an undefined function
= _|_
undef2 _|_
-- defn of undef2
= (\_ -> undefined) _|_
-- application of a lambda
= undefined
-- semantics of undefined
= _|_
类似地,undef1 . id
和 undef2
可以证明在 Hask 中作为态射是等同的(事实上,它们等同于 Haskell 值暗示它们根据 Hask 态射的较弱的相等性定义是相等的),所以没有矛盾。
但是,如果您遵循@n.m.提供的link,您会发现在形式化Haskell值相等的含义方面还有更多工作要做并精确地给出 Hask 态射相等性的适当定义,然后我们才能真正放心地相信 是 无矛盾 Hask 类别。
证明 undef1 . id = undef2
作为 Haskell 值
由于上述原因,这个证明必然有点不正式,但这是我的想法。
如果我们试图见证函数 f
和 g
之间的差异,见证表达式可以 使用 这些值的唯一方法是应用它们的值 x
或使用 seq
将它们评估为 WHNF。如果已知 f
和 g
等于 Hask 态射,那么我们已经对所有 x
有了 f x = g x
,所以没有表达可以见证基于应用的差异。唯一剩下要检查的是,当它们被评估为 WHNF 时,它们要么都已定义(在这种情况下,根据先前的假设,它们在应用时将产生相同的值),要么它们都未定义。
因此,对于 undef1 . id
和 undef2
,我们只需要确保在对 WHNF 求值时它们都已定义或都未定义。很容易看出它们实际上都定义了 WHNFs:
undef1 . id
-- defn of composition
= \x -> undef1 (id x)
-- this is a lambda, so it is in WHNF and is defined
undef2
-- defn of undef2
= \_ -> undefined
-- this is a lambda, so it is in WHNF and is defined
我们已经在上面为所有 x
建立了 undef1 x = undef2 x
。从技术上讲,我们应该证明:
(undef1 . id) x
-- defn of composition
= (\x -> undef1 (id x)) x
-- lambda application
= undef1 (id x)
-- defn of id
= undef1 x
与所有 x
的 Haskell 值相等,这为所有 x
确定了 (undef1 . id) x = undef2 x
。再加上两者都在上面定义了 WHNF,这足以表明 undef1 . id = undef2
与 Haskell 值相等。
https://wiki.haskell.org/Hask:
Consider:
undef1 = undefined :: a -> b undef2 = \_ -> undefined
Note that these are not the same value:
seq undef1 () = undefined seq undef2 () = ()
This might be a problem, because
undef1 . id = undef2
. In order to make Hask a category, we define two functionsf
andg
as the same morphism iff x = g x
for allx
. Thusundef1
andundef2
are different values, but the same morphism in Hask.
这是什么意思或我如何检查:
undef1
和undef2
是不同的值,但是同一个态射?
在 Haskell 中,我们认为每个表达式都可以计算为特定的 "value",我们可能有兴趣确定两个表达式是否具有 "same" 值。
非正式地,我们知道可以直接比较某些值(例如 Integer
类型的值 2
和 3
)。其他值,如 sqrt
和 id
类型 Double -> Double
可以进行比较,正如@pigworker 指出的那样,通过构造一个表达式 "witnesses" 直接比较值的差异:
sqrt 4 = 2
id 4 = 4
这里,我们可以得出结论,sqrt
和id
是不同的值。如果没有这样的见证人,那么价值是一样的。
如果我们查看 undef1
和 undef2
到 () -> ()
类型的单态特化:
undef1, undef2 :: () -> ()
undef1 = undefined
undef2 = \_ -> undefined
我们如何判断这些值是否不同?
好吧,我们需要找到一个可以证明差异的表达式,上面已经给出了一个。两个表达式:
> seq undef1 ()
*** Exception: Prelude.undefined
> seq undef2 ()
()
>
根据 GHCi,具有不同的值。我们也可以直接展示这一点,使用我们对 Haskell 语义的理解:
seq undef1 ()
-- use defn of undef1
= seq undefined ()
-- seq semantics: WHNF of undefined is _|_, so value is _|_
= _|_
seq undef2 ()
-- use defn of undef2
= seq (\_ -> undefined) ()
-- seq semantics: (\_ -> undefined) is already in WHNF and is not _|_,
-- so value is second arg ()
= ()
所以,问题是什么?好吧,当将 Hask 视为一个 类别 时,对象是类型而态射是(单态)函数,我们隐含地需要一个概念 identity/equality 用于对象和态射。
对象 identity/equality 很简单:两个对象(单态 Haskell 类型)当且仅当它们是同一类型时才相等。态射 identity/equality 更难。因为 Hask 中的态射是 Haskell 值(单态函数类型),所以很容易将态射相等定义为与值相等相同,如上所述。
如果我们使用这个定义,那么undef1
和undef2
将是不同的态射,因为我们已经证明它们是不同的Haskell以上值。
但是,如果我们比较 undef1 . id
和 undef2
,我们会发现它们具有 相同的 值。也就是说,没有任何表情可以看出它们之间的区别。证明这有点困难,但请参阅下文。
无论如何,我们现在的 Hask 范畴理论存在矛盾。因为 id
是 Hask 中的(多态族)恒等态射,我们必须有:
undef1
= undef1 . id -- because `id` is identity
= undef2 -- same value
所以我们同时有 undef1 /= undef2
因为上面的见证,但是 undef1 = undef2
由前面的论点。
避免这种矛盾的唯一方法是放弃将 Hask 中的态射相等定义为基础 Haskell 值相等的想法。
已提供的 Hask 中态射相等的另一个替代定义是两个态射 f
和 g
相等的较弱定义,如果和仅当它们满足所有值 x
(包括 _|_
)的 f x = g x
时。请注意,这里仍然存在歧义。如果 f x
和 g x
是 它们自己 Haskell 函数等态射,f x = g x
是否意味着 态射相等 f x
和 g x
或 Haskell 值 f x
和 g x
相等?让我们暂时忽略这个问题。
根据这个替代定义,undef1
和 undef2
是 等同的态射,因为我们可以显示 undef1 x = undef2 x
所有可能的值 x
类型 ()
(即 ()
和 _|_
)。也就是说,应用于 ()
,他们给出:
undef1 ()
-- defn of undef1
= undefined ()
-- application of an undefined function
= _|_
undef2 ()
-- defn of undef2
= (\_ -> undefined) ()
-- application of a lambda
= undefined
-- semantics of undefined
= _|_
并应用于 _|_
他们给出:
undef1 _|_
-- defn of undef1
= undefined _|_
-- application of an undefined function
= _|_
undef2 _|_
-- defn of undef2
= (\_ -> undefined) _|_
-- application of a lambda
= undefined
-- semantics of undefined
= _|_
类似地,undef1 . id
和 undef2
可以证明在 Hask 中作为态射是等同的(事实上,它们等同于 Haskell 值暗示它们根据 Hask 态射的较弱的相等性定义是相等的),所以没有矛盾。
但是,如果您遵循@n.m.提供的link,您会发现在形式化Haskell值相等的含义方面还有更多工作要做并精确地给出 Hask 态射相等性的适当定义,然后我们才能真正放心地相信 是 无矛盾 Hask 类别。
证明 undef1 . id = undef2
作为 Haskell 值
由于上述原因,这个证明必然有点不正式,但这是我的想法。
如果我们试图见证函数 f
和 g
之间的差异,见证表达式可以 使用 这些值的唯一方法是应用它们的值 x
或使用 seq
将它们评估为 WHNF。如果已知 f
和 g
等于 Hask 态射,那么我们已经对所有 x
有了 f x = g x
,所以没有表达可以见证基于应用的差异。唯一剩下要检查的是,当它们被评估为 WHNF 时,它们要么都已定义(在这种情况下,根据先前的假设,它们在应用时将产生相同的值),要么它们都未定义。
因此,对于 undef1 . id
和 undef2
,我们只需要确保在对 WHNF 求值时它们都已定义或都未定义。很容易看出它们实际上都定义了 WHNFs:
undef1 . id
-- defn of composition
= \x -> undef1 (id x)
-- this is a lambda, so it is in WHNF and is defined
undef2
-- defn of undef2
= \_ -> undefined
-- this is a lambda, so it is in WHNF and is defined
我们已经在上面为所有 x
建立了 undef1 x = undef2 x
。从技术上讲,我们应该证明:
(undef1 . id) x
-- defn of composition
= (\x -> undef1 (id x)) x
-- lambda application
= undef1 (id x)
-- defn of id
= undef1 x
与所有 x
的 Haskell 值相等,这为所有 x
确定了 (undef1 . id) x = undef2 x
。再加上两者都在上面定义了 WHNF,这足以表明 undef1 . id = undef2
与 Haskell 值相等。