Haskell自动推导Show实例

5

我正在使用红黑树进行操作:

-- 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" 的显示实例:

<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:为自定义类型推导Show)不起作用。
例如,通过添加以下内容:
instance Show Set where:
    show (Set Char) = show Char

当我尝试使用:l加载时,出现以下错误信息:

:l red-black-tree.hs [1 of 1] Compiling RedBlackTree ( red-black-tree.hs, interpreted )

请注意,这是一个关于IT技术的问题。
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.

我认为在我所尝试做的事情中存在一些问题,但是从可用的文档中似乎无法解决它。


只需使用 data Tree a = ... deriving (Show) - bheklilr
data RBT... 的末尾添加 deriving (Show) 会导致以下错误消息:No instance for (Show Color) arising from the 'deriving' clause of a data type declaration - Joe
只需在 data Color = R | B 的末尾添加 deriving (Show) 即可。 - nponeccop
3个回答

5
为了将一个值转换成字符串,Haskell使用所谓的类型类。简单来说,类型类只是提供函数,这些函数根据其参数的类型表现出不同的行为。这种方法非常类似于面向对象编程语言中的方法重载。类型类“Show”提供了一个名为“show”的函数,它将某种类型的值转换为字符串。例如,表达式“show 1”将生成字符串“"1"”。如果存在一个将某种类型的值转换为字符串的函数“show”,我们就说该类型存在类型类“Show”的实例。换句话说,整数有一个类型类“Show”的实例。
当在ghci中评估表达式时,也会使用此“show”函数。因此,它告诉你不存在一个类型实例“(Show (Set Char))",换句话说,它不知道如何将类型为“Set Char”的值转换为字符串。对于像您的类型“Set”、“RBT”和“Color”这样的自定义类型,您必须提供类型类“Show”的实例,以便在控制台上显示这些类型的值。要为类型“Color”定义类型类“Show”的实例,可以使用以下定义。
instance Show Color where:
  show R = "Red"
  show B = "Black"

也就是说,如果你在ghci中输入 R,它会输出 Red。对于简单的Haskell数据类型,有一个 Show 类型类的规范定义。例如,Color 的规范定义如下。

instance Show Color where:
  show R = "R"
  show B = "B"

为了减轻用户定义实例的负担,Haskell 提供了所谓的“派生机制”。也就是说,如果你写成这样:
  deriving (Show)

在定义数据类型之后,编译器会为您的数据类型生成一个Show类型类的规范实例。如果一个数据类型使用了另一个数据类型,那么对前者派生Show实例将需要后者的Show实例。例如,考虑以下数据类型。
data RBT e = E | T Color (RBT e) e (RBT e)

数据类型RBT在其定义中使用类型ColorT构造函数的规范Show实例将以“T”开头,然后显示Color类型的值。 因此,派生RBTShow实例需要ColorShow实例。

4

你的实例代码有问题:

instance Show Set where
    show (Set Char) = show Char
  1. 编译器提示 Set 不是一个数据构造函数,确实如此-它是类型同义名。所以你在模式中错误地使用了 Set。你应该在那里使用数据构造函数-对于 RBT 数据构造函数是 TE

  2. 你的实例声明不合适:SetRBT 的同义词,RBT 有一个类型参数,即它是从类型到类型的函数,具有带有签名的种类 * -> *。但是,Show 实例需要一种没有参数的类型,即一种类型而不是类型构造函数,种类为 * 而不是你提供的 * -> *。因此,你应该通过提供 instance Show (RBT Char)instance (Show a) => RBT a 来修复它。

你可能想要的是写“通过显示其中的字符来显示 char 集合”。

所以要修复你的实例:

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 aColor的实例。


1
你没有使用任何花哨的扩展,因此应该能够使用内置的“deriving”机制来实现“Show”。为了让它自动派生数据类型的“Show”实例,您类型定义中使用的所有类型也必须具有“Show”实例。只需在所有的“data”定义的末尾添加“deriving (Show)”即可。您可能想养成将“deriving (Eq, Show)”添加到所有“data”类型的习惯,因为您几乎总是需要对类型进行结构相等性测试和可显示性。此外,您不能为“type alias”创建任何类实例,只能为“type”创建。关键字“type”定义了一个类型别名,而不是一个新类型。如果您为您的“RBT a”类型创建一个“Show”实例,则任何声明为“Set a”的内容都将自动使用它,因为“Set a”只是“RBT a”的别名。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接