[英]Are the real Type of Polymorphic Types in Haskell implicitly universally quantified Type?
我试图澄清一些 Haskell 概念。 通过数据声明定义类型时,例如:
data DatumType ab = Datum ab
我一直想知道类型是DatumType
还是隐式forall a. DatumType ab
forall a. DatumType ab
。
因为确实有ExplicitForAll
λ> :set -XExplicitForAll
λ> :k forall a. Maybe a
forall a. Maybe a :: *
λ> :k forall a b . DatumType a b
forall a b . DatumType a b :: *
λ> :k DatumType
DatumType :: * -> * -> *
我们可以看到对于所有forall a b. DatumType ab
forall a b. DatumType ab
是proper type ie *
然而,DatumType 本身只是一个类型构造函数。
因此,这意味着诸如 [a] 之类的多态类型是 TYPE(即 *),并且该类型的全名是forall a. [a]
forall a. [a]
换句话说,我所追求的是确认 Haskell 中多态类型的类型声明始终采用缩写形式,并且完整类型名称始终带有隐式forall a. ....
forall a. ....
也就是说,在data Mytype a
中,类型不是Mytype
,也不仅仅是Mytype a
,而是所有forall a. Mytype a
forall a. Mytype a
,而Mytype
是类型构造函数。
这样的解释正确吗?
我想我会编辑这个问题,以解释所有澄清的来源。 这么说吧,在学习和试验类型类时,我对实例 Eq (a,b) 感到困惑。 为什么不用instance Eq(,),答案不只是因为在实现中需要引用类型变量。 Eq 只能在适当的类型上定义,任何可能的对实际上都是一个类型,一个多态类型。 那么问题来了,但是我们在写data(,)ab = (,)ab的时候定义的是什么。 我是在定义 (,) 还是 forall a b. (a,b)。
推动我与上面的:set -XExplicitForAll
实验一起进行形式化的材料之一是以下声明,摘自此处对 Haskell 的简要介绍,版本 98 - 2 值、类型和其他好东西
Haskell 还包含多态类型——以某种方式对所有类型进行普遍量化的类型。 多态类型表达式本质上描述了类型族。 例如,(forall a)[a] 是类型族,对于每个类型 a,都包含 a 的列表类型。 整数列表(例如 [1,2,3])、字符列表(['a','b','c']),甚至整数列表的列表等,都是这个家族的成员。
定义data DatumType ab = Datum ab
翻译成英文是这样的:
假设有一个名为DatumType
的新类型构造函数和一个名为Datum
的新数据构造函数,这样对于所有类型a
和b
,将Datum
应用于 a 类型a
值和b
类型的值会产生DatumType ab
类型的值。
我一直想知道类型是
DatumType
还是隐式forall a. DatumType ab
forall a. DatumType ab
。
我认为理解这里的障碍是术语“类型”可以有两种不同的含义,具体取决于上下文:
Type
中的任何东西(也称为*
),并且只有这样的东西这两个定义的出现基本上是因为我们使用短语“类型”来描述术语级别的事物与类型级别的事物之间的关系——因此将不能参与该关系的事物包含在含义中似乎很奇怪“类型”。 然而,类型表达式中存在很多不能直接参与这种关系的东西,我们想谈论它们而不必一直使用像“类型级实体”这样笨拙的短语。 作为一个社区,我们似乎没有比在不同时间在这两种意义上使用“类型”更好的解决方案,并希望从上下文中清楚。
所以很明显DatumType
不是定义 2 中的类型; 它需要应用于两个类型参数才能在术语级别产生某种类型。 如果那是我们的想法,那么我可以理解为什么您会倾向于认为数据声明定义的“类型”是forall a b. DatumType ab
forall a b. DatumType ab
。
但是我认为这可能是一种令人困惑的思考方式。 对所有forall a b. DatumType ab
forall a b. DatumType ab
是可以在DatumType _ _
形式的所有类型中使用的术语类型; 这种类型中唯一的值是Datum undefined undefined
之类的东西。 当您看到DatumType ab
时, forall ab
通常会更远; 例如, Datum
构造函数本身的类型(如果您使用 GADT 语法定义它,您将编写它)可以写为Datum:: forall a b. a -> b -> DatumType ab
Datum:: forall a b. a -> b -> DatumType ab
。
所以说“数据声明定义的类型是forall a b. DatumType ab
很奇怪。数据声明定义了整个类型家族,其中类型forall a b. DatumType ab
是一个非常有限的(而且相当无用) example. 相反,我会说“对于所有类型a
和b
,数据声明定义了一个类型DatumType ab
”;所涉及的“for all”概念的 scope 比您在单个类型表达式中用forall
关键字表达的要宽,所以我把它从正式的类型表达中移到了英文描述中。
当然,如果我们专注于“类型”的定义 1,那么事情就更容易解释了。 数据声明简单地定义了类型为* -> * -> *
的DatumType
类型。
这就引出了一个问题:哪种观点是正确的?
或许令人不满意的是,这两种观点之间并没有什么有趣的事情发生。 这两件事都发生了:我们得到一个新的类型构造函数DatumType
,它具有种类* -> * -> *
,并且对于所有类型a
和b
DatumType ab
是一些术语的类型。 这就是 kind * -> * -> *
的意思。 只有当你试图识别“类型”而没有意识到术语类型在这两种意义上都被频繁使用时,才会出现这种困境,所以如果你不清楚自己使用的是哪种意义,你可能会犯错。
一些上下文说没有 kind *
的东西不是类型,因此DatumType
不是真正的类型。 其他人将DatumType
视为一种类型。 然而,这纯粹是我们选择使用的术语的不同; 无论哪种方式, DatumType:: * -> * -> *
都是存在的,并且在任何一种观点中它的功能都相同。 纠结于特定类型级别的实体是否是一种类型并不是事情真正如何运作的问题,这只是英语语言用法的问题。
所以回到你的一些更具体的问题:
因此,这意味着诸如
[a]
之类的多态类型是 TYPE(即 *),并且该类型的全名是 forall a。 [一种]换句话说,我所追求的是确认 haskell 中多态类型的类型声明始终采用缩写形式,并且完整类型名称始终带有隐式
forall a. ....
forall a. ....
正如我提到的,我认为这不太正确。 是的,类型级别的[]
需要一个参数来生成术语类型; []:: * -> *
。 所以根据定义 2, []
不是类型。 然而,说完整列表类型“真的”适用于所有 a 是不正确forall a. [a]
forall a. [a]
,因为它是通用多态列表的特定类型表达式(它只能是空列表的类型,或者充满底部值的列表的类型,或者是底部值的列表)。 特别地, [True, False]
是[Bool]
类型的成员,而不是forall a. [a]
forall a. [a]
。
相反[]
只是种类* -> *
的类型级实体。 你是否称之为类型取决于你。 无论哪种方式,它都不是任何术语的类型,并且无论哪种方式,它都是您可以在类型表达式中使用的有效内容(前提是它们进行了类型检查)。
也就是说,在
data Mytype a
中,类型不是Mytype
,也不仅仅是Mytype a
,而是所有forall a. Mytype a
forall a. Mytype a
,而Mytype
是类型构造函数。
Mytype
是一个类型构造函数。 (在“类型”一词的任一定义中;即使我们乐于将所有类型级别的实体称为类型,“类型构造器”仍然是一个特定的类别,拥有它是一个很好的术语,因为无论某物是否是“类型” constructor”不能仅通过查看其种类来确定,就像您无法仅通过查看其类型来确定某物是否是数据构造函数一样)
Mytype a
本身确实没有意义; 它必须在 scope 中使用,其中类型变量a
在 scope 中。
forall a. Mytype a
forall a. Mytype a
是思考“由data Mytype a
定义的类型”的正确方法。对于任何类型a
Mytype a
都是一种类型;对于所有forall a. Mytype a
是一个特定的类型表达式,不包括我们可以形成的大多数类型Mytype
类型构造函数。
所以任何时候你想使用Mytype a
都会有一个forall
某处(显式或隐式)。 但它通常比立即包含Mytype a
; 像someFunc:: forall a. a -> Bool -> MyType a
someFunc:: forall a. a -> Bool -> MyType a
。
OP 对另一个答案发表了评论,我认为解决这个问题很有见地:
我想我会编辑这个问题,以解释所有澄清的来源。 这么说吧,在学习和试验类型类时,我对
instance Eq (a,b)
感到困惑。 为什么不是instance Eq (,)
,答案不仅仅是因为需要在实现中引用类型变量。Eq
只能在适当的类型上定义,任何可能的对实际上都是一个类型,一个多态类型。 那么问题来了,但是我们在写data (,) ab = (,) ab
的时候定义的是什么。 我是在定义(,)
还是forall a b. (a,b)
forall a b. (a,b)
。
请记住,使类型成为Eq
的实例意味着您可以比较该类型的值是否相等。
当你说instance Eq (a, b)
时,它实际上意味着instance forall a b. Eq (a, b)
instance forall a b. Eq (a, b)
; 在英语中“对于所有类型a
和b
,类型(a, b)
是 class Eq
的成员。这意味着您可以选择任何您喜欢的两种类型,对它们应用(,)
类型构造函数,然后得到结果类型将是一些你可以比较相等的使用值。(这当然不是真的,我们真正使用的实例更像是instance forall a b. (Eq a, Eq b) => Eq (a, b)
,因为我们需要Eq a
和Eq b
)
instance Eq (,)
是错误的,因为它说“类型构造函数 (,) 是 class Eq
的成员”。 “可以比较(,)
的值是否相等”是没有意义的,因为(,)
不是那种可以有值的东西。
但是(,)
仍然是一个存在的东西! 它直接是由data (,) ab = (,) ab
定义的东西。 这只是一种类型* -> * -> *
的东西,这不是我们可以为其创建Eq
实例的那种东西。 短语“ Eq
can only be defined on a proper type”使用的是“type”的定义,它只包含 kind *
的东西,但请记住,这个定义中的“not being a proper type”并不意味着“isn't a real thing”,这只是意味着我们选择(至少在那个特定的句子中)使用具有狭义含义的“类型”一词。 class Eq
被定义为具有 kind *
的成员,仅此而已。 其他类可以定义成有不同种类的东西作为成员; 如果它们有类型* -> * -> *
的成员,则(,)
本身可以是这些类的实例。 例如,查看Bifunctor
的实例列表。 Eq
实例必须是Eq (a, b)
而不是Eq (,)
的事实并不意味着(,)
不是“真正”存在于类型级别的有效实体。
声明书
data DatumType a b = Datum a b
声明一种新类型DatumType
,属于* -> * -> *
。 它还声明了一个新术语Datum
,类型为forall a b. a -> b -> DatumType ab
forall a b. a -> b -> DatumType ab
。
在正常情况下,类型签名确实隐式地普遍量化了它们在顶层提到的所有类型变量。 但是数据声明不是类型签名,所以你的问题的某些部分没有意义。
在启用扩展的情况下,类型变量也有可能是单态的,而不是普遍量化的。 例如,
{-# LANGUAGE ScopedTypeVariables #-}
foo :: forall a. Monoid a => a -> a
foo x = mconcat xs where
xs :: [a]
xs = [x, mempty, x]
在此代码片段中,所有量词都已明确显示。 在 where 块内, xs
具有单态类型[a]
,其中a
是一个类型变量,由封闭类型 scope 绑定,如果插入额外的量词,代码将无法编译:
foo :: forall a. Monoid a => a -> a
foo x = mconcat xs where
xs :: forall a. [a]
xs = [x, mempty, x]
-- type error: can't match type a and type a0, whoops
有了这些信息,希望您的每个陈述的真实状态都更加清楚,但让我们一次一个地浏览它们:
我一直想知道类型是
DatumType
还是隐式forall a. DatumType ab
forall a. DatumType ab
。
无法回答。 什么类型的? DatumType
和forall a. DatumType ab
forall a. DatumType ab
是合法的类型级表达式。
这意味着像 [a] 这样的多态类型是 TYPE,并且该类型的全名是
forall a. [a]
forall a. [a]
。
有时。 量词的插入不是局部过程,而是整个类型签名的全局过程。 它们隐式地浮动到顶层。 所以,这是两种不同的类型:
-- these are all the same with ScopedTypeVariables off
forall a. [a] -> ()
forall a. ([a] -> ())
[a] -> ()
-- this is a different type from the ones above
(forall a. [a]) -> ()
因此,如果在正常的未扩展 Haskell 中编写类型签名x:: [a]
,那么[a]
确实是forall a. [a]
forall a. [a]
; 但是如果你写了签名f:: [a] -> ()
,那么[a]
就不会是forall a. [a]
forall a. [a]
,因为forall
必须从箭头的参数浮动到整个类型。
换句话说,我所追求的是确认 haskell 中多态类型的类型声明始终采用缩写形式,并且完整类型名称始终带有隐式
forall a. ...
forall a. ...
是的。
也就是说,在
data Mytype a
中,类型不是Mytype
,也不仅仅是Mytype a
,而是所有forall a. Mytype a
forall a. Mytype a
, ...
类别错误。 data Mytype a
不是类型签名,所以没有类型。 如果我要从这样的声明中挑出一个类型来调用“类型”,那将是单独的Mytype
,因为这是声明创建的唯一类型。
...而
Mytype
是类型构造函数。
是的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.