我有一些代码可以用来将边缘附加到Node数据结构:
import Data.Set (Set)
import qualified Data.Set as Set
data Node = Vertex String (Set Node)
deriving Show
addEdge :: Node -> Node -> Node
addEdge (Vertex name neighbors) destination
| Set.null neighbors = Vertex name (Set.singleton destination)
| otherwise = Vertex name (Set.insert destination neighbors)
然而,当我尝试编译时,我收到此错误:
No instance for (Ord Node)
arising from a use of `Set.insert'
据我所知,Set.insert只需要一个值和一个插入它的集合。这个奥德是什么?
答案 0 :(得分:6)
在GHCi中:
> import Data.Set
> :t insert
insert :: (Ord a) => a -> Set a -> Set a
是的,它确实期待Ord
。至于Ord
的含义,对于有序值,它是类型类。在这种情况下需要它,因为Data.Set
使用搜索树,因此需要能够比较值以查看哪个更大或者它们是否相等。
几乎所有标准内置数据类型都是Ord
的实例,以及列表,元组,Maybe
等等,当它们的类型为Ord
的实例时参数是。当然,最值得注意的例外是函数,其中没有明确的排序概念(甚至是相等)。
在许多情况下,您可以在声明后使用deriving
子句自动为您自己的数据类型创建类型类的实例:
data Foo a = Foo a a Int deriving (Eq, Ord, Show, Read)
对于参数化类型,自动派生取决于类型参数也是一个实例,就像列表,元组等一样。
除Ord
之外,一些重要的类型类是Eq
(相等比较,但不小于/大于),Enum
(您可以枚举值的类型,例如count {{ 1}} s)和Integer
/ Read
(使用字符串进行简单的序列化/反序列化)。要了解有关类型类的详情,请尝试this chapter in Real World Haskell,或者,对于更一般的概述,请a Wikipedia article。
答案 1 :(得分:4)
Haskell集基于搜索树。为了将元素放在搜索树中,必须给出元素的排序。你可以通过将它添加到数据声明中来推导出Ord,就像你将它显示出来一样,即:
data Node = Vertex String (Set Node)
deriving (Show, Eq, Ord)
您可以通过Data.Set.insert
的签名来查看Ord的要求(Ord a) => a -> Set a -> Set a
部分(Ord a) =>
建立了一个约束,即Ord
的类型类a
的实例。 section on type classes中的haskell tutorial给出了更全面的解释。