Allowing duplicate instances in GHC 6.4
Robert van Herk
rherk at cs.uu.nl
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
data KeysOfDS1 = KDB1_Table1 Int
| KDB1_Table2 Int
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
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...
> 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.
More information about the Glasgow-haskell-users