Given :
data Foo =
FooString String
…
class Fooable a where --(is this a good way to name this?)
toFoo :: a -> Foo
我想让 String
成为 Fooable
的一个实例:
instance Fooable String where
toFoo = FooString
然后GHC抱怨:
Illegal instance declaration for `Fooable String'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Fooable String'
如果相反我使用 [Char]
:
instance Fooable [Char] where
toFoo = FooString
GHC抱怨:
Illegal instance declaration for `Fooable [Char]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are type *variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Fooable [Char]'
Question :
- 为什么我不能创建字符串和类型类的实例?
如果我添加一个额外的标志,C9 GHC似乎愿意让我逃脱这个 . 这是一个好主意吗?
4 回答
这是因为
String
只是[Char]
的类型别名,它只是Char
类型的类型构造函数[]
的应用程序,所以它的形式为([] Char)
. 其格式不是(T a1 .. an)
,因为Char
不是类型变量 .这种限制的原因是为了防止重叠的实例 . 例如,假设您有一个
instance Fooable [Char]
,然后有人出现并定义了instance Fooable [a]
. 现在编译器将无法确定您想要使用哪一个,并且会给您一个错误 .通过使用
-XFlexibleInstances
,您're basically promising to the compiler that you won't定义任何此类实例 .根据您要完成的任务,定义包装器可能更好:
您遇到了经典Haskell98类型类的两个限制:
他们不允许实例中的类型同义词
它们不允许嵌套类型不包含类型变量 .
两个语言扩展提升了这些繁重的限制:
-XTypeSynonymInstances
允许您使用类型synoyms(如
String
用于[Char]
),以及:-XFlexibleInstances
它解除了对实例类型的限制,其形式为
T a b ..
,其中参数是类型变量 .-XFlexibleInstances
标志允许实例声明的头部提及任意嵌套类型 .请注意,解除这些限制有时会导致overlapping instances,此时,可能需要额外的语言扩展来解决歧义,允许GHC为您选择一个实例 .
参考文献::
GHC用户指南中的
在大多数情况下,FlexibleInstances不是一个好的答案 . 更好的替代方法是将String包装在newtype中或引入一个helper类,如下所示:
另见:http://www.haskell.org/haskellwiki/List_instance
除了这些答案之外,如果您不习惯解除限制,可能会出现将String包装在newtype中的情况,新类型可以是类的实例 . 权衡将是潜在的丑陋,必须包装和解包你的代码 .