
I was trying to make a class of "flattenable" data structures in Haskell. My first thought was to use multi-parameter type classes to assert a relation between two data types, one which is flattened and another which holds flattenable elements. Such a class is the class *F* below without the functional dependency. When given an instance declaration like *F Tree []*, applying *flt* to a structure fails with messages like *no instance for `F Tree m`*. I ended up writing the following (where *foldT* is fold over trees, etc.), in order to avoid said errors: class (Functor m, Monad m) => F t m | t -> m where flt :: t a -> m a unflt :: F t' m => t' (t a) -> m a unflt = join . fmap flt . flt instance F Tree [] where flt = foldT (\a b c -> a : b ++ c) [] instance F Maybe [] where flt = maybeToList Now, I would like to have *F* be a relation between a flattenable data type and, for instance, a monoid in which I can accumulate the flattened data type. Two things: I can't get a monoid constraint to operate properly over the variable *m* in *unflt*. This fails with messages like *no instance for `Monoid Tree [Integer]`*, and so on. I'm not sure why. Secondly, I would like to be able to have *flt* be able to return different "container structures", e.g., a custom sequence or a list. But the functional dependency I introduced prohibits this. How would you handle this problem? Thanks.

Hello Dan What is /unflt/ ? I'm presuming it can't be unflatten [*] as I don't see how it would work. If I was making a flatten class, I wouldn't want Monad as a constraint on the result container. Monad doesn't really say anything about "containers" - there are some containers that are Monads, but there are monads that aren't containers and there are containers that aren't monads. The Foldable type class in Data.Foldable is quite like a class for flattenable things, however it folds (flattens) into a monoidal thing (often called a "summary" value). This isn't so good for flattening into a list. List has a monoid instance but it is very inefficient. If you want to flatten into a list-like thing rather than fold into a summary value, you would really need a better class something like "Cons" class Cons t where nil :: t a cons :: a -> t a -> t a By the way, there is no Monoid instance for Data.Tree at least at version containers-0.3.0.0. [*] If you are wanting unflatten as well, things get quite complicated...
participants (2)
-
dan portin
-
Stephen Tetley