根据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
(该类为此提供了两个不同的证明,分别是名称==
和/=
。这个命题是存在性的(不要与存在性类型混淆)
类型类和存在类型之间有什么区别,为什么它们都被认为是“存在的”?
答案 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
,如果 a
是Chaos
的实例,则有一个函数可以将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
时,我们声称Void
是Primordial
的实例。这意味着必须存在一个函数conjure :: Void -> y
,这时我们必须通过提供实现来备份声明。