Class Can';t使String成为Haskell中类的实例

Class Can';t使String成为Haskell中类的实例,class,haskell,Class,Haskell,我在玩弄哈斯克尔的课程。 我写了几行愚蠢的代码来掌握诀窍。我编写了一个名为Slang的类,它只有一个函数。当我将Integer作为类的实例时,它工作得很好。但当我将String作为类的实例时,它不会编译。我一直在根据错误输出告诉我的内容来摆弄程序,但没有用。我知道它为什么会起作用 以下是错误后的代码: module Practice where class Slang s where slangify :: s -> String instance Slang Integer

我在玩弄哈斯克尔的课程。 我写了几行愚蠢的代码来掌握诀窍。我编写了一个名为
Slang
的类,它只有一个函数。当我将Integer作为类的实例时,它工作得很好。但当我将String作为类的实例时,它不会编译。我一直在根据错误输出告诉我的内容来摆弄程序,但没有用。我知道它为什么会起作用

以下是错误后的代码:

module Practice where

class Slang s where
    slangify :: s -> String

instance Slang Integer where
    slangify int = "yo"

instance Slang String where  -- When I take this segment out, it works fine
    slangify str = "bro"
错误:

Prelude> :load Practice
[1 of 1] Compiling Practice         ( Practice.hs, interpreted )

Practice.hs:9:10:
    Illegal instance declaration for `Slang 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 `Slang String'
Failed, modules loaded: none.
Prelude>

问题是字符串不是整数那样的基类型。你想做的实际上是

instance Slang [Char] where
    slangify str = "bro"
然而,Haskell 98禁止这种类型的typeclass,以保持简单,并使人们更难编写像这样的重叠实例

instance Slang [a] where
    -- Strings would also fit this definition.
    slangify list = "some list"

无论如何,正如错误消息所示,您可以通过启用扩展来绕过此限制。

我在Haskell文献(也称为我当前的圣经)中做了一些研究,并找到了一个有效解决我的问题的示例

基本上,在这个解决方法中,您将
Char
设置为类的实例(在本书的示例中,它被称为
Visible
),然后您可以将
[chars]
aka字符串设置为类的实例,并且只需规定类型变量
chars
是“Visible”的实例。 查看下面的代码更容易理解:

module Practice where

class Visible a where
  toString :: a -> String
  size :: a -> Int

instance Visible Char where
  toString ch = [ch]
  size _ = 1

instance Visible a => Visible [a] where
  toString = concat . map toString
  size = foldr (+) 1 . map size
我的GHCi加载和函数调用:

*Practice> :l Practice
[1 of 1] Compiling Practice         ( Practice.hs, interpreted )
Ok, modules loaded: Practice.
*Practice> size "I love Stack!"
14
*Practice>

尤里卡

我写的一篇老博文的无耻插件,探讨了前奏如何绕过这个限制。如何启用FlexibleInstances?@lmay:启用扩展的最简单方法是添加一条注释,如
{-#LANGUAGE FlexibleInstances}
到Haskell文件的顶部。还应该注意的是,使用
Data.Text
,这是一种基本类型,可以在没有任何扩展名的情况下声明实例,而不是
String
。这很聪明,但我认为只有在此类的唯一实例为Char的情况下才有效。如果使用任何其他类型创建实例,则在Visible[a]实例中使用的特定于字符串的函数将不起作用。直到我发布该评论后,我才意识到该线程来自2013年:)