为什么我不能让String成为一个类型类的实例?
鉴于 :
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]'
问题 :
这是因为String
只是[Char]
一个类型别名,它只是类型Char
上类型构造函数[]
的应用,所以这将是形式([] Char)
。 它不是形式(T a1 .. an)
因为Char
不是一个类型变量。
这种限制的原因是为了防止重叠的情况。 例如,假设您有一个instance Fooable [Char]
,然后有人后来出现并定义了一个instance Fooable [a]
。 现在,编译器将无法确定您想使用哪一个,并且会给您一个错误。
通过使用-XFlexibleInstances
,你基本上向编译器保证你不会定义任何这样的实例。
根据你想要完成的事情,定义一个包装可能会更好:
newtype Wrapper = Wrapper String
instance Fooable Wrapper where
...
你遇到了经典的Haskell98类型类的两个局限性:
这些繁重的限制可以通过两种语言扩展来解除:
-XTypeSynonymInstances
它允许你使用类型synoyms(比如[Char]
String
),并且:
-XFlexibleInstances
这提升了对实例类型的限制,其形式为T ab ..
其中参数是类型变量。 -XFlexibleInstances
标志允许实例声明的头部提及任意的嵌套类型。
请注意,消除这些限制有时会导致重叠的实例,此时可能需要额外的语言扩展来解决歧义问题,从而允许GHC为您选择一个实例。
参考文献::
在大多数情况下,FlexibleInstances不是一个好答案。 更好的选择是将字符串包装成新类型或者引入一个助手类,如下所示:
class Element a where
listToFoo :: [a] -> Foo
instance Element Char where
listToFoo = FooString
instance Element a => Fooable [a] where
toFoo = listToFoo
另见:http://www.haskell.org/haskellwiki/List_instance
链接地址: http://www.djcxy.com/p/43509.html