繁体   English   中英

为什么我不能使String成为类型类的实例?

[英]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]'

问题

  • 为什么我不能创建字符串和类型类的实例?
  • 如果我添加一个额外的标志,GHC似乎愿意让我逃脱这个。 这是一个好主意吗?

这是因为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

另见: http//www.haskell.org/haskellwiki/List_instance

除了这些答案之外,如果您不满意解除限制,可能会出现将String包装成newtype(可以是类的实例)的情况。 权衡将是潜在的丑陋,必须包装和解包您的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM