Thanks again Daniel!!

I've been looking at the Edison package, it has a big class hierarchy without default implementations using functional dependencies and I found tidier doing something similar with associated types.

Writing default implementations continues to be troublesome.

Here is an example adding an elems function to the Collection class
 elems :: c -> [Elem c]
I can't write on the MultiMapClass class a default implementation for getValueList like this
 getValueList :: Key m -> m -> [Value m]
 getValueList k m = elems $ getValues k m
because elems returns 
 [Elem (Coll m)]
so I have to write 
 getValueList :: Key m -> m -> [Elem (Coll m)]
and it doesn't matter that this means the same for the implementations I have 
 Elem (Set.Set a) ~ Value (MultiMap k v)
and
 Elem IntSet.IntSet ~ Value IntMultiMap

Now when using classes like this you need to need to think twice when coding! Typing becomes much more complicated.

I don't know if I am too object oriented or is the lack of IDEs but reusing code, grouping together code with similarities and managing many modules is not easy with Haskell. Things that I found essential to write large programs. I'm starting to think that the easiest way of writing generic and reusable code with Haskell is writing a Haskell parser and code generator in Haskell.

On Fri, May 27, 2011 at 3:00 PM, Daniel Fischer <daniel.is.fischer@googlemail.com> wrote:
On Friday 27 May 2011 19:23:54, Federico Mastellone wrote:
> Now I have a new problem, it's getting really difficult to program
> generically and to create highly parameterized libraries.

Yes.

>
> So far so good with type families, but when I want to return a generic
> Set for the getValues function and provide a default implementation for
> getValuesCount function I don't know how to do it, I don't even know if
> it is possible.

You can't return a generic Set in getValues (unless you jump through a lot
of hoops, IntMultiMap has IntSets, so you'd have to transform those to
Sets, ... yuck) and default implementations wouldn't be possible [or at
least rather horrible], but

>
> newtype MultiMap k v = MultiMap (Map.Map k (Set.Set v))
>
> newtype IntMultiMap = IntMultiMap (IntMap.IntMap IntSet.IntSet)

class (Ord (Elem c)) => Collection c where
 type Elem c
 emtpy :: c
 singleton :: Elem c -> c
 size :: c -> Int
 null :: c -> Bool
 member :: Elem c -> c -> Bool
 ...

>
> class MultiMapClass m where

class (Collection (Coll m)) => MultiMapClass m where

>  type Key m
>  type Value m

 type Coll m

>  empty :: m
>  addValue :: Key m -> Value m -> m -> m
>  getValues :: Key m -> m -> Set (Value m)

 getValues :: Key m -> m -> Coll m

>  getValueCount :: Key m -> m -> Int
>  getValueCount k m = Set.size $ getValues k m

 getValueCount k m = size (getValues k m)

Should work or be possible to make working.
But things get more complicated the more generic functionality you want to
add.

It would probably be possible to get a more elegant implementation if you
designed the library to use a class-based interface from the ground up
(take a look at the edison library [EdisonAPI and EdisonCore on hackage]
for an idea of how to structure the classes - edison is old, it was created
long before type families or functional dependencies were available, I
don't know what new stuff was incorporated into it, I suspect not too much,
so you could probably improve the design with the new powerful tools at
your hands, but as a source of inspiration, it should still serve well).

The problem is that, as a rule of thumb, class based genericity costs
performance. And the point of the containers package was to provide
performant data structures, the genericity was wilfully forsaken.

So, perhaps writing a generic envelope for the containers types might not
be the best option. It could be better to start from a clean sheet.
[disclaimer: I have not thought about how to do that, nor looked at the API
or implementation from that point of view, so my hunch may be quite wrong.]

Cheers,
Daniel




--
Federico Mastellone
Computer Science Engineer - ITBA

".. there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult."
Tony Hoare, 1980 ACM Turing Award Lecture.