为什么我不能让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和实例?
  • 如果我添加一个额外的标志,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为您选择一个实例。


    参考文献::

  • 在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

    上一篇: Why can I not make String an instance of a typeclass?

    下一篇: How do I typehint away this reflection warning?