https://wiki.haskell.org/Hask:
考虑:
undef1 = undefined :: a -> b undef2 = \_ -> undefined
请注意,这些值不相同:
seq undef1 () = undefined seq undef2 () = ()
这可能是一个问题,因为
undef1 . id = undef2
。为了使 Hask 成为一个类别,我们将两个函数f
和g
定义为相同的态射,如果所有f x = g x
都x
。因此undef1
和undef2
是不同的值,但 Hask 中的态射相同。
这是什么意思或我如何检查:
undef1
和undef2
是不同的值,但是相同的态射?
答案 0 :(得分:4)
在Haskell中,我们有这样的想法,即每个表达式都可以被评估为特定的"值",我们可能有兴趣确定两个表达式是否具有"相同的"值。
非正式地,我们知道可以直接比较某些值(例如,类型2
的值3
和Integer
)。其他值,例如类型sqrt
的{{1}}和id
,可以像@pigworker指出的那样,通过构建一个表达式来表达"见证"直接可比值的差异:
Double -> Double
在此,我们可以得出结论:sqrt 4 = 2
id 4 = 4
和sqrt
是不同的值。如果没有这样的证人,那么价值是相同的。
如果我们查看id
和undef1
对undef2
类型的单形特化:
() -> ()
我们如何判断这些值是否不同?
好吧,我们需要找到一个见证差异的表达,上面给出了一个。两个表达式:
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值。
但是,如果我们比较undef2
和undef1 . id
,我们会发现它们具有相同的值。也就是说,没有任何表达能见证它们之间的差异。证明这有点困难,但见下文。
无论如何,我们现在在 Hask 类别理论中存在矛盾。因为undef2
是 Hask 中的(多态系列)身份态射,我们必须:
id
所以我们同时拥有undef1
= undef1 . id -- because `id` is identity
= undef2 -- same value
因为上面的见证,但前一个论点是undef1 /= undef2
。
避免这种矛盾的唯一方法是放弃将 Hask 中的态射等同定义为基础Haskell值的相等性的想法。
已经提供的 Hask 中的态射等同的另一个定义是两个态射undef1 = undef2
和f
相等的较弱定义,当且仅当它们满足{时{1}}表示所有值g
(包括f x = g x
)。请注意,这里仍然存在歧义。如果x
和_|_
本身 Haskell函数及其态射,则f x
表示态射 g x
的相等性和f x = g x
或Haskell 值相等 f x
和g x
?我们暂时忽略这个问题。
根据此替代定义,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
= _|_
可以通过此定义显示为 Hask 中的态射(事实上,它们等于Haskell值,这意味着它们&# 39;根据 Hask 态射的平等的较弱定义,相等,所以没有矛盾。
但是,如果你按照@nm提供的链接,你可以看到在形式化Haskell值相等的含义方面还有更多的工作要做,并准确地给出 Hask 态射之前我们确实感到很自在,认为 是一个无矛盾的 Hask 类别。
undef1 . id
为Haskell值由于上述原因,这个证据必然是非正式的,但这就是这个想法。
如果我们试图见证函数undef2
和undef1 . id = undef2
之间的差异,见证表达式使用这些值的唯一方法是将它们应用于值{ {1}}或使用f
将其评估为WHNF。如果已知g
和x
等于 Hask 态射,那么我们已经为所有seq
提供了f
,因此没有任何表达可以见证根据应用程序的差异。唯一要检查的是,当它们被评估为WHNF时,它们要么被定义(在这种情况下,按照先前的假设,它们将在应用时产生相同的值),或者它们都是未定义的。
因此,对于g
和f 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值相等。