Allowing duplicate instances in GHC 6.4

Robert van Herk rherk at
Fri Mar 25 16:55:21 EST 2005

Keean Schupke wrote:

> Just thought I ought to point out that all this is only necessary if 
> the datasources may return different types... If you want them to 
> return the same type you only need:
> instance (Datasource l k v,Datasource r k v) => Datasource (JoinedDS l 
> r) k v ...
> As both datasources have the same key and value types, you then choose 
> which 'v' to return at the value level.

Nono, the datasources I have implemented are a type safe means to 
extract (key,value) pairs from a data store. The idea is that this way, 
in a type safe fashion, e.g. database access can be abstract.

I use HaskellDB as the database access layer, and then define a 
datasource instance for any given database, so that the user does not 
need to think about the details of the actual database access: he can 
just read and write from the datasource, and the datasource will make 
sure the actual queries will be executed.

My idea now was that if I have 2 databases, and I construct datasources 
for them, it would be really cool if I was able to unite them, so that 
the programmer in the end could talk two 1 datasource, that allowed for 
accessing the 2 databases at one entry point. This was what I was making 
the JoinedDS for.

So, suppose I have 2 datasources for two different databases. One may 
have keys:
data KeysOfDS1 = KDB1_Table1 Int
                            |  KDB1_Table2 Int

 and values
data ValuesOfDS1 = VDB1_Table1 (Int,Int,String)
                                | VDB2_Table2 (Int,Int,String)

and the other one:
data KeysOfDS2 = KDB2_Table1 String
                            |  KDB2_Table2 String
data ValuesOfDS2 = VDB2_Table1 (String, Float)
                                | VDB2_Table2 (String, Float, Int)

Now, these datastructures correspond to the actual tables in the 
database. My toolset will generate datasources for these types, thus we 
have instances:

instance Datasource Database1 KeysOfDS1 ValuesOfDS1
instance Datasource Database2 KeysOfDS2 ValuesOfDS2

and the cool thing would be, to combine these two datasources at a 
higher level in my datasources graph, so that I would have 1 datasource 
that found out by itself which actual datasource to use, thus:

x = JoinedDS  db1 db2 -- where dbx is a datasource Databasex KeysOfDSx 

Now, I would want the user to be able to read both KeysOfDS1 (which 
would yield a ValuesOfDS1) as well as KeysOfDS2 (which would yield a 
ValuesOfDS2) from x.

Herefore, I need the instances mentioned before:
instance (Datasource l k v) => Datasource (JoinedDS l r) k v where
 dsread (JoinedDS l r) k = let (l, v) = dsread l k in (JoinedDS l r, v)
instance (Datasource r k v) => Datasource (JoinedDS l r) k v where
 dsread (JoinedDS l r) k = let (r, v) = dsread r k in (JoinedDS l r, v)

But this, thus, yields duplicate instance errors, which I don't like :-).


P.S. Sorry for any typos, I am enjoying a rather nice bottle of wine :-).

> I am not sure whether you intended Datasources to contain 
> heterogeneous key or value types, and whether the loolup is supposed 
> to be value or type driven. My original answer assumed a single 
> Datasource contains values of different types, selected by the type of 
> the key...
>    Keean.
> Robert van Herk wrote:
>> Yes, but this is not what I want. I want to be able to give a key 
>> that either the left or the right data source would take, and then 
>> return the appropriate value. Thus: if I pass it a key that would 
>> normally go into l, I want the value l returns me to be returned, and 
>> if I pass it the key that would normally go into r, I want to return 
>> the value r returns me.
>> The datasource class has a function dsread :: ds -> k -> (ds, v) -- 
>> read may have a side effect
>> Thus I want want to do something like:
>> instance (Datasource l k v) => Datasource (JoinedDS l r) k v where
>>  dsread (JoinedDS l r) k = let (l, v) = dsread l k in (JoinedDS l r, v)
>> instance (Datasource r k v) => Datasource (JoinedDS l r) k v where
>>  dsread (JoinedDS l r) k = let (r, v) = dsread r k in (JoinedDS l r, v)
>> It would be perfectly okay to me when the compiler would complain if 
>> the key and value that go into l and r are the same, but for any 
>> useful purpose I can think of (e.g. glueing two database couplings 
>> together, since I also made a Datasource instance for database 
>> access), this will not happen and the duplicate instances should not 
>> really occur, since the context of the instances makes sure only 1 
>> will be possible.
>> However, GHC only looks at the RHS (thus: Datasource (JoinedDS l r) k 
>> v) and then decides that both instances are the same.
>> So, my question was: how to overcome this.
>> Thanks,
>> Robert

More information about the Glasgow-haskell-users mailing list