How can I use HaskellDB with polymorphic fields? (Problems with overlapping instances)

With the age of this question, it is probably too late of an answer to make any difference to you, but maybe if some other person comes along with a similar problem…

It comes down to the fact that it cannot be inferred that you want entity to refer to Book when branch is used in masterHead. The part of the error message that reads

The choice depends on the instantiation of `entity0′

tells you where you need to remove the ambiguity, specifically that you need to give more information about what entity0 should be. You can give some type annotations to help things out.

First, define branch as

type BranchTable entity = Table (RecCons (Revision entity) (Expr (Revision entity)) RecNil)
branch :: BrancTable entity
branch = baseTable "branch" $ hdbMakeEntry undefined

and then change masterHead to read

masterHead :: Query (Rel (RecCons (Revision Book) (Expr (Revision Book)) RecNil))
masterHead = do
  revisions <- table bookRevision
  branches <- table (branch :: BranchTable Book)
  restrict $ revisions ! revIdField .==. branches ! revIdField
  return revisions

Note the type annotation applied to branch: branch :: BranchTable Book which serves to remove the ambiguity that was causing the type error.

To make masterHead applicable to anything with a Revision e field in it, you can use this definition:

masterHead :: (ShowRecRow r, HasField (Revision e) r) => Table r -> e -> Query (Rel r)
masterHead revTable et =
  do  revisions <- table revTable
      branches <- table branch'
      restrict $ revisions ! revIdField' .==. branches ! revIdField'
      return revisions
  where (branch', revIdField') = revBundle revTable et
        revBundle :: HasField (Revision e) r => Table r -> e -> (BranchTable e, Attr (Revision e) (Revision e))
        revBundle table et = (branch, revIdField)

The et argument is needed to specify what the e type should be and can just be undefined ascribed to the proper type as in

masterHead bookRevision (undefined :: Book)

which generates the SQL

SELECT rev_id1 as rev_id
FROM (SELECT rev_id as rev_id2
      FROM branch as T1) as T1,
     (SELECT rev_id as rev_id1
      FROM book_revision as T1) as T2
WHERE rev_id1 = rev_id2

this does require FlexibleContexts though, but it can be applied to the asker’s module without recompiling HaskellDB.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)