Class 在haskell中定义多类型容器类,绑定变量时遇到问题
我在哈斯克尔的课上遇到了麻烦 基本上,我有一个算法(一种奇怪的图形遍历算法),它将一个容器作为输入,用来存储已经看到的节点(我热衷于避免单子,所以让我们继续:)。问题是,该函数将容器作为参数,只调用一个函数:“set_contains”,它询问容器是否。。。包含节点v。(如果您好奇的话,另一个作为参数传入的函数会执行实际的节点添加) 基本上,我想尝试各种数据结构作为参数。然而,由于没有重载,我不能让一个以上的数据结构使用最重要的contains函数 所以,我想做一个“设置”类(我知道我不应该自己做)。多亏了Chris Okasaki的书,我已经建立了一个非常漂亮的红黑树,现在剩下的就是创建set类并声明RBT,以及其他一些实例 以下是代码: (注意:代码大量更新——例如,contains现在不调用帮助函数,而是类函数本身!)Class 在haskell中定义多类型容器类,绑定变量时遇到问题,class,haskell,functional-programming,Class,Haskell,Functional Programming,我在哈斯克尔的课上遇到了麻烦 基本上,我有一个算法(一种奇怪的图形遍历算法),它将一个容器作为输入,用来存储已经看到的节点(我热衷于避免单子,所以让我们继续:)。问题是,该函数将容器作为参数,只调用一个函数:“set_contains”,它询问容器是否。。。包含节点v。(如果您好奇的话,另一个作为参数传入的函数会执行实际的节点添加) 基本上,我想尝试各种数据结构作为参数。然而,由于没有重载,我不能让一个以上的数据结构使用最重要的contains函数 所以,我想做一个“设置”类(我知道我不应该自己
数据颜色=红色|黑色
数据(Ord a)=>RBT a=树叶|树木颜色(RBT a)a(RBT a)
实例显示颜色在哪里
显示红色=“r”
显示黑色=“b”
类集合t在哪里
包含::(Ord a)=>t->a->Bool
--我知道这是毫无意义的,只是表明它可以编译。
实例(Ord a)=>等式(RBT a),其中
叶=叶=真
(Tree uux ux)==(Tree uuy)=x==y
实例(Ord a)=>集合(RBT a),其中
包含叶b=False
包含t@(树c l x r)b
|b==x=True
|b
注意,我有一个非常愚蠢的RBT Eq实例。这是故意的——我是从别人那里抄来的(但抄近路)
基本上,我的问题可以归结为:如果我注释掉Set的实例化语句(rbta),那么一切都可以编译。如果我将其重新添加,则会出现以下错误:
RBTree.hs:21:15:
Couldn't match expected type `a' against inferred type `a1'
`a' is a rigid type variable bound by
the type signature for `contains' at RBTree.hs:11:21
`a1' is a rigid type variable bound by
the instance declaration at RBTree.hs:18:14
In the second argument of `(==)', namely `x'
In a pattern guard for
the definition of `contains':
b == x
In the definition of `contains':
contains (t@(Tree c l x r)) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
RBTree.hs:21:15:
无法将预期的类型“a”与推断的类型“a1”匹配
`a'是一个刚性类型变量,由
RBTree中“contains”的类型签名。hs:11:21
`a1'是一个刚性类型变量,由
RBTree上的实例声明。hs:18:14
在“(==)”的第二个参数中,即“x”
以防
“包含”的定义:
b==x
在“包含”的定义中:
包含(t@(树c l x r))b
|b==x=True
|b
就我的一生而言,我根本无法弄明白为什么这不起作用。(作为旁注,“contains”函数在别处定义,基本上具有RBT数据类型的实际set_contains逻辑。)
谢谢阿戈尔
第三次编辑:删除以前的编辑,合并在上面。错误意味着类型不匹配。
包含的类型是什么?(如果它的类型不是像t->a->Bool
那样的set\u所包含的is,那么就有问题了。)为什么你认为不应该滚动自己的类
为Set(RBT a)
编写实例时,只为特定类型a
定义contains。也就是说,RBT Int
是一组Int
s,RBT Bool
是一组Bools
,等等
但是您对Set t
的定义要求t
同时是所有有序a
的集合
也就是说,鉴于包含的类型,这应该进行类型检查:
tree :: RBT Bool
tree = ...
foo = contains tree 1
显然不会
有三种解决方案:
使t
成为类型构造函数变量:
类集合t在哪里
包含::(Ord a)=>TA->a->Bool
实例集RBT在哪里
...
这适用于RBT
,但不适用于许多其他情况(例如,您可能希望将位集用作Int
s的集合)
功能依赖性:
类(Ord a)=>设置TA | t->a其中
包含::t->a->Bool
实例(Ord a)=>集合(RBT a)a,其中
有关详细信息,请参阅
相关类型:
类集合t在哪里
类型元素t::*
包含::t->元素t->Bool
实例(Ord a)=>集合(RBT a),其中
类型元素(RBT a)=a
有关详细信息,请参见。您需要一个多参数类型类。您当前对集合t
的定义没有在类定义中提及包含的类型,因此成员包含的必须适用于任何a
。请尝试以下操作:
class Set t a | t -> a where
contains :: (Ord a) => t-> a-> Bool
instance (Ord a) => Set (RBT a) a where
contains Leaf b = False
contains t@(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
为了扩展Ganesh的答案,您可以使用类型族而不是函数依赖项。我认为它们更好。而且它们对代码的更改也更少
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
class Set t where
type Elem t
contains :: (Ord (Elem t)) => t -> Elem t -> Bool
instance (Ord a) => Set (RBT a) where
type Elem (RBT a) = a
contains Leaf b = False
contains (Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
{-#语言灵活上下文,类型族}
类集合t在哪里
类型元素t
包含::(Ord(要素t))=>t->要素t->Bool
实例(Ord a)=>集合(RBT a),其中
类型元素(RBT a)=a
包含叶b=False
包含(树c l x r)b
|b==x=True
|b
您也可以使用。您的类的定义方式需要一个具有*的类型t。您可能想要的是您的集合类采用一个容器类型,就像您的RBT具有kind*->*
通过将t
应用于类型变量,您可以轻松修改类以赋予类型t一种*->*,如下所示:
class Set t where
contains :: (Ord a) => t a -> a -> Bool
然后修改实例声明以删除类型变量a
:
instance Set RBT where
contains Leaf b = False
contains t@(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
实例集RBT,其中
包含叶b=False
包含t@(树c l x r)b
|b==x=True
|b
下面是使用sma修改的完整代码
class Set t where
contains :: (Ord a) => t a -> a -> Bool
instance Set RBT where
contains Leaf b = False
contains t@(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
data Color = Red | Black
data (Ord a) => RBT a = Leaf | Tree Color (RBT a) a (RBT a)
instance Show Color where
show Red = "r"
show Black = "b"
class Set t where
contains :: (Ord a) => t a -> a -> Bool
-- I know this is nonesense, just showing it can compile.
instance (Ord a) => Eq (RBT a) where
Leaf == Leaf = True
(Tree _ _ x _) == (Tree _ _ y _) = x == y
instance Set RBT where
contains Leaf b = False
contains t@(Tree c l x r) b
| b == x = True
| b < x = contains l b
| otherwise = contains r b
tree = Tree Black (Tree Red Leaf 3 Leaf) 5 (Tree Red Leaf 8 (Tree Black Leaf 12 Leaf))
main =
putStrLn ("tree contains 3: " ++ test1) >>
putStrLn ("tree contains 12: " ++ test2) >>
putStrLn ("tree contains 7: " ++ test3)
where test1 = f 3
test2 = f 12
test3 = f 7
f = show . contains tree
tree contains 3: True
tree contains 12: True
tree contains 7: False