9

我正在尝试理解 Haskell 中的类。我写了几行愚蠢的代码来掌握它。我写了一个名为的类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>
4

2 回答 2

14

问题是 String 不是像 Integer 这样的基本类型。你想要做的实际上是

instance Slang [Char] where
    slangify str = "bro"

然而,Haskell98 禁止这种类型的类型类,以使事情变得简单,并使人们更难编写重叠的实例,例如

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

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

于 2013-03-08T02:54:52.713 回答
5

我对我的 Haskell 文献(也就是我现在的圣经)进行了一些研究,并找到了一个可以有效解决我的问题的例子。

基本上,在这个解决方法中,您设置Char为类的一个实例(在本书的示例中,它被称为Visible),然后您可以将[chars]aka 字符串设置为该类的一个实例,前提是类型变量chars是一个“可见”的实例。如果你看下面的代码会更容易理解:

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>

尤里卡!

于 2013-03-08T03:48:43.817 回答