Hask甚至是一个类别?

时间:2018-01-28 11:08:12

标签: haskell category-theory

https://wiki.haskell.org/Hask

  

考虑:

undef1 = undefined :: a -> b
undef2 = \_ -> undefined
     

请注意,这些值不相同:

seq undef1 () = undefined
seq undef2 () = ()
     

这可能是一个问题,因为undef1 . id = undef2。为了使 Hask 成为一个类别,我们将两个函数fg定义为相同的态射,如果所有f x = g xx。因此undef1undef2是不同的,但 Hask 中的态射相同。

这是什么意思或我如何检查: undef1undef2是不同的值,但是相同的态射?

1 个答案:

答案 0 :(得分:4)

在Haskell中,我们有这样的想法,即每个表达式都可以被评估为特定的"值",我们可能有兴趣确定两个表达式是否具有"相同的"值。

非正式地,我们知道可以直接比较某些值(例如,类型2的值3Integer)。其他值,例如类型sqrt的{​​{1}}和id,可以像@pigworker指出的那样,通过构建一个表达式来表达"见证"直接可比值的差异:

Double -> Double

在此,我们可以得出结论:sqrt 4 = 2 id 4 = 4 sqrt是不同的值。如果没有这样的证人,那么价值是相同的。

如果我们查看idundef1undef2类型的单形特化:

() -> ()

我们如何判断这些值是否不同?

好吧,我们需要找到一个见证差异的表达,上面给出了一个。两个表达式:

undef1, undef2 :: () -> ()
undef1 = undefined
undef2 = \_ -> undefined
根据GHCi,

有不同的价值观。我们也可以使用我们对Haskell语义的理解直接显示这个:

> seq undef1 ()
*** Exception: Prelude.undefined
> seq undef2 ()
()
>

那么,问题是什么?好吧,当将 Hask 视为时,对象是类型,而态射是(单态)函数,我们隐含地需要对象和态射的同一性/等式的概念。

对象标识/相等很容易:当且仅当它们是相同类型时,两个对象(单态Haskell类型)是相等的。态射身份/平等更难。因为 Hask 中的态射是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 () = () undef1将是不同的态射,因为我们已经证明它们是上面不同的Haskell值。

但是,如果我们比较undef2undef1 . id,我们会发现它们具有相同的值。也就是说,没有任何表达能见证它们之间的差异。证明这有点困难,但见下文。

无论如何,我们现在在 Hask 类别理论中存在矛盾。因为undef2 Hask 中的(多态系列)身份态射,我们必须:

id

所以我们同时拥有undef1 = undef1 . id -- because `id` is identity = undef2 -- same value 因为上面的见证,但前一个论点是undef1 /= undef2

避免这种矛盾的唯一方法是放弃将 Hask 中的态射等同定义为基础Haskell值的相等性的想法。

已经提供的 Hask 中的态射等同的另一个定义是两个态射undef1 = undef2f相等的较弱定义,当且仅当它们满足{时{1}}表示所有值g(包括f x = g x)。请注意,这里仍然存在歧义。如果x_|_ 本身 Haskell函数及其态射,则f x表示态射 g x的相等性和f x = g x或Haskell 值相等 f xg x?我们暂时忽略这个问题。

根据此替代定义,f xg 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 = _|_ 可以通过此定义显示为 Hask 中的态射(事实上,它们等于Haskell值,这意味着它们&# 39;根据 Hask 态射的平等的较弱定义,相等,所以没有矛盾。

但是,如果你按照@nm提供的链接,你可以看到在形式化Haskell值相等的含义方面还有更多的工作要做,并准确地给出 Hask 态射之前我们确实感到很自在,认为 是一个无矛盾的 Hask 类别。

证明undef1 . id为Haskell值

由于上述原因,这个证据必然是非正式的,但这就是这个想法。

如果我们试图见证函数undef2undef1 . id = undef2之间的差异,见证表达式使用这些值的唯一方法是将它们应用于值{ {1}}或使用f将其评估为WHNF。如果已知gx等于 Hask 态射,那么我们已经为所有seq提供了f,因此没有任何表达可以见证根据应用程序的差异。唯一要检查的是,当它们被评估为WHNF时,它们要么被定义(在这种情况下,按照先前的假设,它们将在应用时产生相同的值),或者它们都是未定义的。

因此,对于gf x = g x,我们只需要确保它们在被评估为WHNF时既定义了又两者都未定义。事实上,它们很容易看出它们都定义了WHNF:

x

我们已在上面建立了所有undef1 . id的{​​{1}}。从技术上讲,我们应该表明:

undef2

将所有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 的Haskell值相等,为所有undef1 x = undef2 x建立x。加上两者都定义了上面的WHNF这一事实,这足以证明(undef1 . id) x -- defn of composition = (\x -> undef1 (id x)) x -- lambda application = undef1 (id x) -- defn of id = undef1 x 与Haskell值相等。