使用Haskell 98 decls时,整个数据类型必须为newtype
或data
。但是数据族可以混合使用newtype instance
和data instance
。这是否意味着newtype
是数据构造函数的属性,而不是数据类型的属性?可能会出现Haskell,例如:
data Foo a = MkFoo1 Int a
| MkFoo2 Bool a
| newtype MkFoo3 a
我知道我不能写以下内容,但是为什么/出了什么问题?:
data family Bar a
newtype instance Bar (Maybe Int) = MkBar1 (Maybe Int)
-- MkBar1 :: (Maybe Int) -> Bar (Maybe Int), see below
newtype instance Bar [Char] = MkBar2 [Char]
data instance Bar [Bool] where
MkBar3 :: Int -> Bool -> Bar [Bool]
-- can't be a newtype because of the existential Int
-- we're OK up to here mixing newtypes and data/GADT
data instance Bar [a] where
MkBar4 :: Num a => a -> Bar [a]
-- can't be a newtype because of the Num a =>
我不能这样写,因为实例头Bar [a]
与MkBar2, MkBar3
的两个头重叠。然后,我可以通过在where ...
的{{1}}内移动这两个构造函数decl来解决此问题。但是随后Bar [a]
成为GADT(因为其结果类型不是MkBar2
),所以不能成为Bar [a]
。
然后是newtype
的结果类型属性,而不是构造函数的属性吗?但是,请考虑上面针对新类型实例newtype
推断的类型。我无法编写具有相同类型的顶级MkBar1
newtype
嗯? newtype Baz a where
MkBaz :: (Maybe Int) -> Baz (Maybe Int)
-- Error: A newtype constructor must have a return type of form T a1 ... an
是一个新类型构造函数,其类型不是这种形式。
如果可能的话,请在不深入探讨角色的情况下进行解释:我试图理解它们;只会伤到我的头讨论这些构造函数的构造和模式匹配。
答案 0 :(得分:1)
您可以将数据族视为(内射和开放式)族的更强版本。从this question I asked a while back中可以看出,数据族几乎可以被内射型族伪造。
这是否意味着成为newtype是数据构造函数的属性而不是数据类型?可能会出现Haskell,例如:
data Foo a = MkFoo1 Int a | MkFoo2 Bool a | newtype MkFoo3 a
不。肯定是newtype
是类型构造函数的属性,而不是数据构造函数的属性。数据家族与类型家族非常相似,具有两个级别的类型构造函数:
data/type family FamTyCon a
data/type instance FamInstTyCon a = ...
的类型构造器同一data/type
系列构造函数的不同实例仍然在根本上是不同的类型-它们恰好在一个类型构造函数下统一(并且该类型构造函数将是内射和生成的-有关更多信息,请参见链接的问题)。 )。
根据类型家族的类比,您不会期望能够对TyFam a
类型的对象进行模式匹配,对吗?因为您可能拥有type instance TyFam Int = Bool
和type instance TyFam () = Int
,并且无法静态知道自己正在查看Bool
还是Int
!
答案 1 :(得分:0)
这些是等效的:
newtype NT a b = MkNT (Int, b)
data family DF a b
newtype instance DF a b = MkDF (Int, b)
-- inferred MkNT :: (Int, b) -> NT a b
-- MkDF :: (Int, b) -> DF a b
此外,您无法声明族DF
中的任何其他实例/构造函数,因为它们的实例头将重叠DF a b
。
q重新独立的新类型Baz
中的错误消息具有误导性
-- Error: A newtype constructor must have a return type of form T a1 ... an
(大概是数据族之前的日期)。新类型的构造函数必须具有与实例头完全相同的返回类型(如果使用GADT语法,则以模数重命名)。对于独立的新类型,“实例头”表示newtype
头。
对于非新类型数据实例,各种构造函数的返回类型可能比实例头更严格(这使它们成为GADT)。
在数据/新类型实例头中声明的类型(在文献中被不同地称为“类型方案”,“单型”(因为没有约束,称为“无功能类型”),在2008年论文“具有类型检查”中) “开放类型函数”)是所有构造函数的返回类型必须统一的主体类型。 (可能没有任何具有该返回类型的构造函数。)
如果您的实例是newtype
,则规则要严格得多:只能有一个构造函数,并且其返回类型必须恰好是主体类型。所以要回答原来的q
这是否意味着
newtype
是数据构造函数的属性,而不是数据类型的属性? ...但是...那么newtype
是结果类型的属性,而不是构造函数的属性吗?
不,不是构造函数的;是的,更像是结果:作为新类型是数据族实例/其主体类型的属性。只是对于独立的新类型,实际上只能有一个实例,并且其主体类型是该类型构造函数的最通用类型。派生地,我们可以说新类型的主体类型/返回类型唯一地标识数据构造函数。这对于类型安全至关重要,因为@AlexisKing的评论指出,该类型的值与新类型的数据构造函数中的类型共享其表示形式,即没有包装器。然后,模式匹配就不需要去寻找构造函数了:匹配是无可辩驳的/构造函数是虚拟的。
令我惊讶的是,为了获得更精确的键入/更好的文档,您可能希望将一个新类型声明为只有一个实例的数据族,其实例比您为独立的新类型必须放置的头更具体。 / p>