Allowing duplicate instances in GHC 6.4
k.schupke at imperial.ac.uk
Fri Mar 25 18:09:09 EST 2005
Robert van Herk wrote:
> 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 :-).
Thats because they overlap in 'k'. However you can change the fundep:
>class Datasource s k v | s -> k v
>instance Datasource DB1 K1 V1
>instance Datasource DB2 K2 V2
>instance (Datasource l k' v',TypeEq k k' z,Datasource' z l r k v) =>
Datasource (JoinedDS l r) k v where
>class Datasource' z l r k v | z l r -> k v
>instance Datasource l k v => Datasource' TTrue l r k v
>instance Datasource r k v => Datasource' TFalse l r k v
Here I have used TypeEq from the HList library to determine if the type
parameter k is the same type as the k' from datasource l. This lets k
determine which instance from the other class gets used.
More information about the Glasgow-haskell-users