我正在尝试在Haskell98中做一些抽象但不知道该怎么做。
我想要做的是为可以转换为列表的类型定义一个类。
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
我该怎么做?
答案 0 :(得分:9)
另请参阅标准库中的Data.Foldable,它为任何toList
实例提供Foldable
函数。 Foldable
需要一些复杂的实例化,但这将是一个好习惯。作为奖励,您的HTree
类型与文档中的示例实例几乎完全相同。
此外,我建议您将HTree
更改为:
data HTree a = Nil | Node a (HTree a) (HTree a)
然后使用HTree (a,b)
代替HTree a b
。这个单参数版本可以更容易地与标准类型和实例组合,并且它可以更多地达到正在发生的事情,因为它以相同的方式依赖于两个参数。它也是Functor
,定义这样的实例会使这种类型非常适合使用。
答案 1 :(得分:4)
我建议Type classes are not as useful as they first seem - 如果推定的类只有一个接口方法,请考虑声明一个函数类型。我也来自OO背景,发现我花了太多时间试图让“课堂”意味着我认为的意思,当我真的应该使用“数据”时。
只需编写你的toList'功能然后'解除'它就可以对你的数据结构进行操作。事实上,备受赞誉的Yet Another Haskell Tutorial经历了一次广泛的练习,展示了它是如何完成的,并以二叉树为例。升力的好处在于它区分了什么是重要的 - 数据类型的结构,而不是toList'的实现 - 所以一旦完成提升以执行'按顺序遍历数据类型',你可以使用电梯来实现做任何事 - toList,print等等。支持toList不是数据结构的重要部分,因此它不应该在类声明中 - 重要的部分是如何遍历数据结构。
答案 2 :(得分:-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]