我正在阅读真实世界Haskell 第151页,我已经盯着以下段落一个多小时了:
回想一下,String是一个同义词 [Char],反过来又是[a]的类型 其中Char代替了类型 参数a。根据Haskell 98的说法 规则,我们不允许提供 键入时代替类型参数 我们写一个实例。换一种说法, 写一篇文章对我们来说是合法的 [a]的实例,但不是[Char]的实例。 16条评论5335
它只是没有下沉。盯着the (free not pirated) copy of RWH chapter 6我看到很多的其他人真的很痛苦。我仍然不理解评论......
首先,关于这一切的一切都让我感到困惑,所以如果您觉得可以解释有关此段落的任何内容,请{I} TypeSynonymInstances
。
这是我的问题:
Int
是数据构造函数 String
是数据构造函数 AND 类型同义词 现在我无法回答这些问题:
谢谢!
答案 0 :(得分:27)
我认为问题的一部分是两个很大程度上不相关的限制:
data
或newtype
声明的内容,而不是type
。这禁止String
,但不禁止[Char]
。Maybe Int
和f Int
,但不禁止Maybe a
。以下是GHCi对Int
,Char
和String
所说的内容:
data Char = GHC.Types.C# GHC.Prim.Char#
data Int = GHC.Types.I# GHC.Prim.Int#
type String = [Char]
Int
和Char
都是没有类型变量参数的简单类型;没有涉及类型构造函数,因此您可以非常自由地使用它们创建实例。
字符串在两个计数上失败。它是一个类型的同义词,这是不允许的,它也是应用于非变量的类型构造函数,即应用于Char的列表类型构造函数。
为了进行比较,请注意[a]
,Maybe a
和Either a b
在实例中均有效,但[Int]
,Maybe [a]
和{{1}被禁止;希望你现在能明白为什么。
关于你的直接问题,我不知道用这种方式设计语言的原始动机是什么,而且我没有资格做出关于“最佳实践”的权威性陈述,而是我自己的个人编码我真的不犹豫地使用这些pragma:
Either String a
你总是可以去看packages that use pragmas。看起来,灵活的实例确实得到了相当多的使用,并且来自“可敬的”软件包(例如,在Parsec的源代码中有几个点击)。
答案 1 :(得分:10)
实际上,Int
和String
都不是数据构造函数。也就是说,您不能使用它们来创建
> (Int 42, String "bob")
<interactive>:1:1: Not in scope: data constructor `Int'
<interactive>:1:9: Not in scope: data constructor `String'
Int
命名一种新的,不同的代数数据类型。 String
是已存在类型的“类型同义词”或别名:[Char]
。问题是Haskell 98说你不能在实例声明中使用类型同义词。
我不能说为什么Haskell 98报告的作者在这种情况下选择限制类型同义词。它们有很多限制。例如,它们不能被部分应用(如果它们采用类型参数)。我认为§4.2.2结尾处有一条线索:
类型同义词很方便,但是 严格的句法,制作机制 类型签名更具可读性。一个 同义词及其定义是 完全可以互换,除了 实例的实例类型 声明(第4.3.2节)。
据推测,有一种程序编译方法,这种语法可互换性会导致实例出现问题。也许它与它们从包中泄漏的实例的显着方面有关...
至于你的上一个问题,我认为这个解释会混淆两件事:1)String
是[Char]
的类型同义词,而[a]
又是一般类型{{1}的特化2)即使没有同义词,[Char]
也不能在实例的头部使用。
第二个问题与类型同义词无关,但是实例头必须将类型构造函数的所有类型参数都设置为变量,而不是具体类型。也就是说,您无法为某些类定义[Int]
和[Char]
的单独实例,您只能定义实例[a]
。 (请记住,尽管语法很方便,[]
是一个类型构造函数,里面的东西是类型参数。)
同样,我不知道为什么报告会限制这些,但我怀疑它也与编译策略有关。由于GHC的实例编译策略可以处理这个问题,因此您可以通过-XFlexibleInstances
在GHC中放宽此约束。
最后,我看到两个扩展都在相当多的代码中启用,但也许具有更多Haskell经验的人可以权衡它们是否是“最佳实践”或不是。
答案 2 :(得分:1)
Haskell 98
因此使用instance ClassName TypeConstructor where
和TypeConstructor 必须如Int
,Double
或[a]
是有效的,请确保只有[]
涉及类型构造函数!!
BTW,[TypeConstructor]
是类型构造函数,因此无法使用[NewType]
,但允许使用[TypeVariable]
和{{1}}。
这是Haskell的限制,我们可以通过启用FlexibleInstances来避免它。
答案 3 :(得分:0)
Int和String是类型,而不是数据构造者。字符串恰好是[Char]的别名,也可以写为List Char。数据构造函数类似于Just,因此Just 3是Maybe Int类型的值。这里解释了类型同义词实例:
http://hackage.haskell.org/trac/haskell-prime/wiki/TypeSynonymInstances