为什么说类型类是存在的?

时间:2019-07-01 02:21:52

标签: haskell typeclass

根据this link describing existential types

  

存在类型的值,例如∃x。 F(x)是一对包含x类型和F(x)类型值的对。而像∀x这样的多态类型的值。 F(x)是采用某种x类型并产生F(x)类型值的函数。在这两种情况下,类型都在某个类型构造函数F上关闭。

但是具有类型类约束的函数定义不会与类型类实例配对。

不是forall f, exists Functor f, ...(因为很明显并非每个类型f都有Functor f的实例,因此exists Functor f ...不是真的)。​​

它不是exists f and Functor f, ...(因为它适用于满足f的所有实例,不仅适用于选定的那个)。

对我来说,它是forall f and instances of Functor f, ...,更像是scala的隐式参数,而不是存在的类型。

根据this link describing type classes

  

[Eq的类声明在逻辑上意味着存在一个类型a -> a -> Bool被居住的类型a,或者从a可以证明a -> a -> Bool(该类为此提供了两个不同的证明,分别是名称==/=。这个命题是存在性的(不要与存在性类型混淆)

类型类和存在类型之间有什么区别,为什么它们都被认为是“存在的”?

2 个答案:

答案 0 :(得分:7)

您引用的Wiki是错误的,或者至少是不精确的。 声明类不是存在命题;它不是任何形式的命题,而只是速记的定义。然后,如果您愿意的话,可以继续使用该定义提出一个建议,但它本身并非如此。例如,

class Eq a where (==) :: a -> a -> Bool

进行新定义。然后,人们可以使用它写一个不存在,不普遍的命题,例如,

Eq ()

我们可以通过以下方式“证明”:

instance Eq () where () == () = True

或者可以写

prop_ExistsFoo :: exists a. Eq a *> a

作为存在命题。 (Haskell实际上没有exists命题前体,也没有(*>)。将(*>)视为(=>)的对偶-就像exists是对偶的对偶forall。因此,(=>)是一个接受约束证据的函数,(*>)是一个包含约束证据的元组,就像forall是用于exists包含一个类型的元组时接受一个类型。)我们可以通过例如

“证明”该命题
prop_ExistsFoo = ()

请注意,exists元组中包含的类型为()(*>)元组中包含的证据就是我们上面编写的Eq ()实例。我很高兴Haskell倾向于在此处使类型和实例保持沉默和隐式,这样它们就不会出现在可见的证明文字中。

类似地,我们可以通过写类似

的东西,在Eq中做出一个不同的普遍主张。
prop_ForallEq :: forall a. Eq a => a

不是不可证明的,或者

prop_ForallEq2 :: forall a. Eq a => a -> a -> Bool

例如可以通过编写来“证明”

prop_ForallEq2 x y = not (x == y)

或其他许多方式。

但是类声明本身绝对不是一个存在命题,并且它不具有“存在性”,无论这意味着什么。不要为这个挂断而感到困惑,而是祝贺您自己正确地将此错误主张标记为令人困惑!

答案 1 :(得分:2)

第二个引用不准确。存在性要求与实例有关,而不与类本身有关。考虑以下课程:

class Chaos a where
    to :: a -> y
    from :: x -> a

虽然这是一个非常有效的声明,但不可能有Chaos的任何实例(曾经有to . from存在,这很可笑)。例如to ...

的类型
GHCi> :t to
to :: Chaos a => a -> y

...告诉我们,给定任何类型的a,如果 aChaos的实例,则有一个函数可以将a转换为任何类型的值。如果Chaos没有实例,则该声明完全是虚假的,因此我们无法从中推断出任何此类函数的存在。

暂时搁置课程,这种情况与the absurd function的情况非常相似:

absurd :: Void -> a

此类型表示,给定Void值,我们可以产生任何类型的值。听起来很荒谬,但是后来我们记得Void是空类型,这意味着没有Void值,而且很好。

为对比起见,我们可能会注意到,一旦我们将Chaos分为两个类,实例就成为可能了:

class Primordial a where
    conjure :: a -> y

class Doom a where
    destroy :: x -> a


instance Primordial Void where
    conjure = absurd

instance Doom () where
    destroy = const ()

例如,当我们写instance Primordial Void时,我们声称VoidPrimordial的实例。这意味着必须存在一个函数conjure :: Void -> y,这时我们必须通过提供实现来备份声明。