字符串和[a]实例

时间:2015-07-30 13:08:27

标签: haskell instance typeclass

作为练习,我决定在Haskell中实现一个Blank类型的类(其中blank在空,False或只有空格的String时为真。我开始,简单地说,就像人们可能:

class Blank a where
  blank :: a -> Bool

instance Blank Bool where
  blank = not

instance Blank [a] where
  blank = null

当我去实施String实例时:

instance Blank String where
  blank [] = True
  blank (' ':xs) = blank xs
  blank ('\t':xs) = blank xs
  blank ('\n':xs) = blank xs
  blank ('\r':xs) = blank xs
  blank _ = False

我遇到了错误:

Illegal instance declaration for `Blank 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 `Blank String'

我很确定它是因为[a]String是多余的,即String[Char])是{的更具体的实例{1}}。

有没有办法绕过这个并定义一个更具体的实例(即[a])?

1 个答案:

答案 0 :(得分:1)

有一个标准的技巧可以以优雅的方式实现你想要的东西。 如果你想想你想做什么,你应该记住一个使用它的标准和非常常用的类:Show

也许你从来没有考虑show [1,2,3] == "[1, 2, 3]" show "hello" == "\"hello\""的问题,但问题是一样的。解决此问题的方法是向showList :: [a] -> ShowS类添加Show操作,为其添加默认定义,然后为通用列表提供实例。

在您的情况下,您需要以下内容:

import Data.Char(isSpace)

class Blank a where
  blank :: a -> Bool
  blankList :: [a] -> Bool
  blankList = null

instance Blank a => Blank [a] where
  blank = blankList

instance Blank Char where
  blank = isSpace

  blankList [] = True
  blankList (' ':xs) = blankList xs
  blankList ('\t':xs) = blankList xs
  blankList ('\n':xs) = blankList xs
  blankList ('\r':xs) = blankList xs
  blankList _ = False

通过这种方式,只要您在列表上调用blank,就会调用相应的blankList方法。使用的方法是列表的元素实例提供的方法,因此Char实例可以定义blankList以在列表中返回True非空,但只包含空格等,而其他实例只能使用null的默认实现。

此实现的缺点是您必须将String的操作放入Char的实例中。但是没有办法解决它:在Haskell 98/2010中,您只能有一个类型构造函数和类的实例,因此一旦定义了Blank [a]实例,就不能使用[]来包含其他实例,其中包括String {1}}。

使用Blank [a]的实例替换Blank a => Blank [a]的实例,您只能为[] 定义一个实例,但其行为会根据实例的变化而变化Blank a因此您可以使用特殊情况String

另一种解决方案是简单地处理String,正如已经说过的那样。您始终可以定义:

newtype MyString = MyString String

然后使用MyString代替String