2008-11-21 88 views
8

我想在Haskell98中做一些抽象,但不知道如何去做。haskell类型类中的多个类型参数

我想要做的是为可能转换为列表的类型定义一个类。

toList :: a -> [b] 

但我不知道如何定义此方法的类。我提出了以下三个想法:

class ToList a b where 
    toList :: a -> [b] 

class ToList a where 
    toList :: a -> [b] 

class ToList a where 
    toList :: a b -> [b] 

第一个不起作用,因为Haskell98不允许多个参数类。

第二个不起作用,因为b依赖于a而不能为每个b实现。

第三个不起作用,因为我不知道如何实例化类的类型'b'不是最后一个类型参数。

data HTree a b = Nil | Node a b (HTree a b) (HTree a b) 

toList Nil = [] 
toList Node x y l r = toList l ++ [(x,y)] ++ toList r 

toList Nil = [] 
toList Node x y l r = toList l ++ [x] ++ toList r 

我怎么会做这样的事情?

回答

8

也参见在标准库,它提供了一种用于任何Foldable实例toList功能Data.FoldableFoldable需要一些复杂的实例化,但这将是一个很好的做法。作为奖励,您的HTree类型与文档中的示例实例几乎完全相同。

另外,我建议您更改HTree到:

data HTree a = Nil | Node a (HTree a) (HTree a) 

,然后使用HTree (a,b),而不是HTree a b。这个单参数版本将更容易与标准类型和实例组合起来,并且它更接近正在发生的事情,因为它以相同的方式依赖于两个参数。这也是一个Functor,定义这样一个实例将使这种类型真的很好用。

4

我推荐Type classes are not as useful as they first seem - 如果推定的类只有一个接口方法,可以考虑声明一个函数类型。我也来自OO背景,发现我花了太多时间试图让“课堂”意味着我的意思,当时我真的应该使用“数据”。

只要编写你的toList函数然后'提升'它来操作你的数据结构就简单多了。实际上,备受好评的Yet Another Haskell Tutorial经过了广泛的练习,展示了它是如何完成的,并以二叉树为例。关于完成提升的好处是区分什么是重要的 - 数据类型的结构,而不是toList的实现 - 所以一旦提升完成执行'为了遍历数据类型',你可以使用升降机做任何事 - toList,打印,不管。支持toList不是数据结构的重要组成部分,因此它不应该在类声明中 - 重要的是如何遍历数据结构。

-1

您可能想要选择类ToList的最后一个选项,并使ToList的实例成为(HTree a)。然后toList具有类型 (HTree a b) -> [b],例如不是(HTree a b) -> [(a,b)]。我假设你正在考虑一个“关键”和b作为“价值”类型。

class ToList a where 
    toList :: a b -> [b] 

data HTree a b = Nil | Node a b (HTree a b) (HTree a b) 

instance ToList (HTree a) where 
    toList Nil = [] 
    toList (Node x y l r) = toList l ++ [y] ++ toList r 

test = toList (Node "a" 1 (Node "b" 2 Nil Nil) Nil) 
-- test == [2,1]