Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple type parameters in haskell type classes

I'm trying to do some abstraction in Haskell98 but doen't know how to do it.

What I want to do is to define a class for types that may be converted into lists.

toList :: a -> [b]

But I don't know how to define a class for this method. I brought up the following three ideas:

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

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

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

The first one doesn't work because Haskell98 doesn't allow multiple parameter classes.

The second one doesn't work because b depends on a and can't be implemented for every b.

The third doesn't work either because I don't know how to instanciate the class with a type where 'b' isn't the last type-parameter.

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

or

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

How would I do something like that?

like image 838
Thomas Danecker Avatar asked Feb 04 '23 12:02

Thomas Danecker


2 Answers

See also Data.Foldable in the standard library, which provides a toList function for any Foldable instance. Foldable takes a bit of sophistication to instantiate, but it would be good practice. As a bonus, your HTree type is almost exactly the same as the example instance in the documentation.

Additionally, I recommend changing your HTree to:

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

And then using HTree (a,b) instead of HTree a b. This single-parameter version will be more easily composable with standard types and instances, and it gets more to the point of what is going on since it depends on both parameters in the same way. It is also a Functor, and defining such an instance will make this type really nice to work with.

like image 114
luqui Avatar answered Feb 06 '23 03:02

luqui


I'd recommend Type classes are not as useful as they first seem - if the putative class has just one interface method, consider declaring a function type instead. I came from an OO background too and found I spent far too much time trying to make "class" mean what I thought it meant, when really I should have been using "data".

It is much easier just to write your toList' function and then 'lift' it to operate on your data structure. In fact, the acclaimed Yet Another Haskell Tutorial goes through an extensive exercise showing how it's done, and uses a binary tree as the example. The great thing about doing a lift is it distinguishes what is important - the structure of the datatype, not the implementation of toList' - so once the lift is done to perform 'in order traversal of the datatype', you can use the lift to do anything - toList, print, whatever. Supporting toList isn't the important part of the data structure, so it shouldn't be in a class declaration - the important part is how to traverse the data structure.

like image 37
Chris Avatar answered Feb 06 '23 02:02

Chris