具有多个参数的Haskell和TypeClass
在编写相互继承的类型类时,我遇到了一个简单的问题。我试图创建类型类的层次结构,以实现某种程度的表示抽象。假设我想要一个集合类型类:具有多个参数的Haskell和TypeClass,haskell,Haskell,在编写相互继承的类型类时,我遇到了一个简单的问题。我试图创建类型类的层次结构,以实现某种程度的表示抽象。假设我想要一个集合类型类: {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} class Collection c a where isMember :: a -> c -> Bool 我定义了一种树类型: data Tree a = Empty | Node a (Tree
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
class Collection c a where
isMember :: a -> c -> Bool
我定义了一种树类型:
data Tree a = Empty | Node a (Tree a) (Tree a)
deriving (Show, Eq)
我想让我的树成为一个收藏,因此:
inOrder :: Tree a -> [a]
inOrder Empty = []
inOrder (Node a l r) = (inOrder l) ++ [a] ++ (inOrder r)
instance (Eq a) => Collection (Tree a) a where
isMember a c = a `elem` (inOrder c)
这不太合适:
*Main> (isMember '2' Empty)
<interactive>:1:1:
No instance for (Collection (Tree a) Char)
arising from a use of `isMember' at <interactive>:1:1-18
Possible fix:
add an instance declaration for (Collection (Tree a) Char)
In the expression: (isMember '2' Empty)
In the definition of `it': it = (isMember '2' Empty)
*Main>(isMember'2'为空)
:1:1:
(集合(树a)字符)没有实例
因在1:1-18使用“isMember”而产生
可能的解决方案:
为(集合(树a)字符)添加实例声明
在表达式中:(isMember'2'为空)
在“it”的定义中:it=(isMember“2”为空)
如果我必须为每个具体类型创建一个实现,那么typeclass的值可能会丢失。所以我没有正确地编写实例声明。但是我不太清楚如何继续。您需要添加一个函数依赖项,以指示容器类型决定元素类型:
{-# LANGUAGE FunctionalDependencies #-}
class Collection c a | c -> a where
...
还有其他方法可以做到这一点,比如使用类型族,但我认为这是这种情况下最简单的解决方法。问题是
Empty
的类型是树a
,ghc没有足够的信息来知道在这种情况下希望a
是字符。如果手动指定类型,则它将起作用:
isMember '2' (Empty::Tree Char)
ghc不能仅仅推断a
必须是Char
的原因是理论上可以有一个实例Collection(Tree Char)Char
和另一个Collection(Tree Int)Char
。在这种情况下,除非您明确指定,否则无法推断应该使用哪一个。这里的问题是,默认情况下,每个类型类参数都独立于其他参数。简单地将isMember
应用于Char
和未知元素类型的树不足以让它推断应该使用(看似明显的)实例
这显然不是你想要的工作方式,启动有点傻,但这就是它的工作方式。为了解决这个问题,您需要为它提供某种连接方式,对于这种连接还有其他扩展:FunctionalDependencies
是更常见的,而TypeFamilies
是更新的,更易于使用,但仍然有一些粗糙的边缘
对于函数依赖关系,您可以指定类型类参数的某些子集完全决定其他参数,例如集合c a | c->a
。这有其自身的缺陷,但在许多情况下效果足够好
对于类型族,您可能会将其简化为单个参数类型类,并关联元素类型,例如:
class Collection c where
type Elem c
isMember :: Elem c -> c -> Bool