我正在玩红黑树:
-- Taken from Okasaki 1999
module RedBlackTree where
--node coloring data
--a node is R (red) or B (black)
data Color = R | B
--tree constructor
--a RBT can be E (empty) or be T (a non empty tree)
data RBT e = E | T Color (RBT e) e (RBT e)
--set operations on tree
type Set a = RBT a
--define an empty set
empty :: Set e
empty = E
--define a member of a set
--Sees if an item of type e is
--in a set if type e elements
member :: (Ord e) => e -> Set e -> Bool
member x E = False
member x (T _ a y b) | x < y = member x a -- if less, go left
| x == y = True
| x > y = member x b -- if more, go right
--tree operations
--Insert an element
insert :: (Ord e) => e -> Set e -> Set e
insert x s = makeBlack (ins s)
where ins E = T R E x E --basically the typical BST insert
ins (T color a y b) | x < y = balance color (ins a) y b
| x == y = T color a y b
| x > y = balance color a y (ins b)
makeBlack (T _ a y b) = T B a y b --inserts a black node
-- balance operations
--case 1:
balance B (T R (T R a x b) y c) z d = T R (T B a x b) y (T B c z d)
--case 2:
balance B (T R a x (T R b y c)) z d = T R (T B a x b) y (T B c z d)
--case 3:
balance B a x (T R (T R b y c) z d) = T R (T B a x b) y (T B c z d)
--case 4:
balance B a x (T R b y (T R c z d)) = T R (T B a x b) y (T B c z d)
--generic balancing operation
balance color a x b = T color a x b
如果我在GHCi中执行以下语句:
> RedBlackTree.insert ('b') (RedBlackTree.T R E ('a') E)
以下错误消息告诉我,Set Char
没有show的实例:
<interactive>:116:1:
No instance for (Show (Set Char)) arising from a use of `print'
Possible fix: add an instance declaration for (Show (Set Char))
In a stmt of an interactive GHCi command: print it
我知道树正在工作,因为通过调用member 'b' ...
...
是先前执行的语句,返回的值是True
。我一直在阅读关于这个问题的其他SO帖子,但找到的解决方案(例如:Haskell: Deriving Show for custom type)不起作用。
例如,添加:
instance Show Set where:
show (Set Char) = show Char
当我尝试使用:l
加载时收到以下错误消息:
:l red-black-tree.hs [1 of 1]编译RedBlackTree(red-black-tree.hs,解释)
red-black-tree.hs:54:11: Not in scope: data constructor `Set'
red-black-tree.hs:54:15: Not in scope: data constructor `Char'
red-black-tree.hs:54:28: Not in scope: data constructor `Char'
Failed, modules loaded: none.
我认为我正在尝试做的事情有一些问题,但我似乎无法从可用的文档中找到答案。
答案 0 :(得分:5)
要将值转换为字符串,Haskell使用所谓的类型类。简化后,类型类只提供根据其参数类型而行为不同的函数。这种方法与面向对象编程语言中已知的方法重载非常相似。类类Show
提供了一个名为show
的函数,它将某种类型的值转换为字符串。例如,表达式show 1
生成字符串"1"
。如果有一个函数show
将某种类型的值转换为字符串,我们就说这种类型有一个类型为Show
的实例。换句话说,对于整数,存在类型类Show
的实例。
当您在ghci中计算表达式时,也会使用此show
函数。因此,它告诉您没有实例(Show (Set Char))
,换句话说,它不知道如何将类型Set Char
的值转换为字符串。对于类型Set
,RBT
和Color
等自定义类型,您必须提供类型类Show
的实例,以便在控制台上显示这些类型的值。要为类型Show
定义类型类Color
的实例,可以使用以下定义。
instance Show Color where:
show R = "Red"
show B = "Black"
也就是说,如果您将R
写入ghci,它将打印Red
。对于简单的Haskell数据类型,存在Show
类型类的规范定义。例如,Show
的{{1}}的规范定义如下。
Color
为了减轻用户定义这样的实例,Haskell提供了一种所谓的“派生机制”。也就是说,如果你写
instance Show Color where:
show R = "R"
show B = "B"
在定义数据类型之后,编译器将为您的数据类型生成 deriving (Show)
类型类的规范实例。
如果数据类型使用其他数据类型,则派生前者的Show
实例将需要后者的Show
实例。例如,请考虑以下数据类型。
Show
数据类型data RBT e = E | T Color (RBT e) e (RBT e)
在其定义中使用类型RBT
。 Color
构造函数的规范Show
实例将以“T”开头,然后显示类型T
的值。因此,为Color
导出Show
实例需要RBT
Show
的实例。
答案 1 :(得分:4)
您的实例代码已损坏:
instance Show Set where
show (Set Char) = show Char
编译器抱怨Set
不是数据构造函数,而不是 - 它是类型的同义词名称。所以你在模式中错误地使用了Set
。您可以在那里使用数据构造函数 - RBT
数据构造函数为T
和E
。
你的实例声明是错误的:Set
是RBT
的同义词,RBT
有一个类型参数,也就是说它是一个从一个类到另一个类型的函数, * -> *
的亲切签名。但是Show
实例需要一个没有参数的类型,这是一个类型,而不是一个类型构造函数,类型*
而不是您提供的* -> *
。因此,您应该通过提供instance Show (RBT Char)
或instance (Show a) => RBT a
。
你可能想要的是写“通过在其中显示字符来显示一组字符”。
所以要修复你的实例:
instance Show (RBT Char) where
show a = "something"
但它没有显示任何有用的东西。你需要在RBT的构造函数上进行模式匹配才能完成工作:
instance Show (RBT Char) where
show E = "something"
show (T a b c d) = "something else"
但是对于您的任务,仅使用Show
和RBT a
的派生Color
实例会更简单。
答案 2 :(得分:1)
您没有使用任何花哨的扩展程序,因此您应该能够使用deriving
的内置Show
机制。
为了使其自动派生数据类型的Show
实例,类型定义中使用的所有类型也必须具有Show
个实例。只需将deriving (Show)
添加到data
定义的所有的末尾即可。您可能希望养成将deriving (Eq, Show)
添加到所有data
类型的习惯,因为您几乎总是需要结构相等性测试和类型的可显示性。
此外,您不能为类型别名创建任何类的类实例,仅适用于类型。关键字type
定义了类型别名,而不是新类型。如果您为Show
类型设置RBT a
个实例,它会自动用于您声明为Set a
的任何内容,因为Set a
只是{{1}的别名}}