作为练习,我决定在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]
)?
答案 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
。