[英]Why can I not make String an instance of a typeclass?
鉴于 :
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不是一个好的答案。 更好的替代方法是将String包装在newtype中或者引入一个helper类,如下所示:
class Element a where
listToFoo :: [a] -> Foo
instance Element Char where
listToFoo = FooString
instance Element a => Fooable [a] where
toFoo = listToFoo
除了这些答案之外,如果您不满意解除限制,可能会出现将String包装成newtype(可以是类的实例)的情况。 权衡将是潜在的丑陋,必须包装和解包您的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.