为什么我不能让String成为一个types类的实例?
鉴于 :
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和types类的实例?
- GHC似乎愿意让我摆脱这个,如果我加一个额外的标志。 这是一个好主意吗?
这是因为String
只是[Char]
一个types别名,它只是typesChar
上的types构造函数[]
的应用,所以这将是([] Char)
的forms。 这不是forms(T a1 .. an)
因为Char
不是一个typesvariables。
这个限制的原因是为了防止重叠的情况。 例如,假设你有一个instance Fooable [Char]
,然后有人来了,并定义了一个instance Fooable [a]
。 现在编译器将无法确定你想使用哪一个,并会给你一个错误。
通过使用-XFlexibleInstances
,你基本上向编译器保证你不会定义任何这样的实例。
根据你想要完成的事情,定义一个包装可能会更好:
newtype Wrapper = Wrapper String instance Fooable Wrapper where ...
你遇到了经典的Haskell98types的两个限制:
- 它们在实例中不允许types同义词
- 他们不允许嵌套的types不包含typesvariables。
这些繁重的限制由两种语言扩展解除:
-
-XTypeSynonymInstances
它允许您使用types的synoyms(如[Char]
String
),并且:
-
-XFlexibleInstances
这解除了实例types的限制,其forms为T ab ..
其中参数是typesvariables。 -XFlexibleInstances
标志允许实例声明的头部提及任意的嵌套types。
请注意,解除这些限制有时会导致重叠的实例 ,此时可能需要额外的语言扩展来解决歧义,从而允许GHC为您select一个实例。
参考文献 :
- 在GHC用户指南中放宽实例头的规则 。
在大多数情况下,FlexibleInstances并不是一个好的答案。 更好的替代方法是将string包装成新的types,或者引入一个助手类,如下所示:
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
除了这些答案之外,如果你不习惯解除这些限制,可能会出现这样的情况:将你的string换成新types,这可能是类的一个实例。 权衡是可能的丑陋,必须在你的代码中打包和解包。