2011-11-12 30 views
50

Mam schemat, który ma 6 różnych typów obiektów, ale wszystkie mają wiele wspólnych cech. Doszedłem do wniosku, że mogłem prawdopodobnie wyprowadzić wiele z tej wspólności na poziomie typu, ale mam problem z HaskellDB i nakładającymi się instancjami. Oto kod Zacząłem, który działa dobrze:Jak mogę użyć HaskellDB z polami polimorficznymi? (Problemy z nakładającymi się instancjami)

import Database.HaskellDB 
import Database.HaskellDB.DBLayout 

data Revision a = Revision deriving Eq 
data Book = Book 

instance FieldTag (Revision a) where 
    fieldName _ = "rev_id" 

revIdField :: Attr (Revision Book) (Revision Book) 
revIdField = mkAttr undefined 

branch :: Table (RecCons (Revision Book) (Expr (Revision Book)) RecNil) 
branch = baseTable "branch" $ hdbMakeEntry undefined 
bookRevision :: Table (RecCons (Revision Book) (Expr (Revision Book)) RecNil) 
bookRevision = baseTable "book_revision" $ hdbMakeEntry undefined 

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

Działa to dobrze, ale branch jest zbyt szczegółowe. Co faktycznie chcę wyrazić to:

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

Jednakże, z tą zmianą, pojawia się następujący błąd:

Overlapping instances for HasField 
          (Revision Book) 
          (RecCons (Revision entity0) (Expr (Revision entity0)) RecNil) 
    arising from a use of `!' 
Matching instances: 
    instance [overlap ok] HasField f r => HasField f (RecCons g a r) 
    -- Defined in Database.HaskellDB.HDBRec 
    instance [overlap ok] HasField f (RecCons f a r) 
    -- Defined in Database.HaskellDB.HDBRec 
(The choice depends on the instantiation of `entity0' 
To pick the first instance above, use -XIncoherentInstances 
when compiling the other instance declarations) 
In the second argument of `(.==.)', namely `branches ! revIdField' 
In the second argument of `($)', namely 
    `revisions ! revIdField .==. branches ! revIdField' 
In a stmt of a 'do' expression: 
     restrict $ revisions ! revIdField .==. branches ! revIdField 

próbowałam ślepo rzucać -XOverlappingInstances i -XIncoherentInstances na to, ale że nie pomaga (i chciałbym zrozumieć, dlaczego zastąpienie konkretnego typu zmienną typu powoduje, że jest to problematyczne).

Każda pomoc i porada będą mile widziane!

+0

Zgodnie z instrukcją obsługi http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#undecidable-includes IncoherentInstances należy dodać do Database.HaskellDB. HDBRec, aby odnieść skutek. –

+0

W szczególności: chęć nałożenia się na siebie lub niespójności jest własnością samej deklaracji instancji, kontrolowanej przez obecność lub nieobecność flag -XOverlappingInstances i -XIncoherentInstances podczas definiowania tego modułu. –

Odpowiedz

2

Z wiekiem to pytanie, to chyba zbyt późno z odpowiedzią na to żadnej różnicy do ciebie, ale może jeśli jakaś inna osoba przychodzi wraz z podobnym problemem ...

To sprowadza się do Fakt, że nie można wywnioskować, że chcesz entity odnosić się do Book, gdy branch jest używany w jest używany w jest używany w . Część komunikat o błędzie

The choice depends on the instantiation of `entity0'

powie Ci, gdzie trzeba usunąć niejasności, zwłaszcza, że ​​trzeba dać więcej informacji na temat tego, co powinno być entity0. Możesz podać adnotacje typu, aby pomóc.

Najpierw zdefiniuj branch jak

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

a następnie zmienić masterHead czytać

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 

Uwaga typ adnotacji zastosowany do branch: branch :: BranchTable Book który służy do usunięcia niejasności, który powodował błąd typu .

Aby masterHead zastosowanie do niczego z Revision e pola w nim, można skorzystać z tej definicji:

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) 

et argumentem jest potrzebne, aby określić, jaki typ e powinno i może być po prostu undefined przypisywana odpowiedniego typu jak w

masterHead bookRevision (undefined :: Book) 

który wytwarza 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 

wymaga to jednak FlexibleContexts, ale można go zastosować do modułu pytającego bez rekompilacji HaskellDB.

+0

Nie za późno! To po prostu interesująca praca hobbystyczna, więc nie ma terminów :) Nie wydaje się to jednak rozwiązać problemu. Nie chcę definiować klasy masterHead pod względem książki, ponieważ ma ona być polimorficzna w typie jednostki. Istnieją inne podmioty, które również mają masterHead (wydawcy, wydania). Sednem tego jest to, że te typy encji mają być zdefiniowane poza pakietem z masterHead, ponieważ elementy masterHead muszą być dostarczane z podstawowej struktury wewnętrznej. – ocharles

+0

@ charles, więc chcesz, aby 'masterHead' wziął parametr tabeli bazowej zamiast używać' bookRevision'? –

+0

OK, spojrzał ponownie - tak, masterHead jest również parametryczny, ponieważ te inne typy również mają pomysł "masterHead". Myślę, że chciałem również to zrobić bez konieczności przekazywania dodatkowych typów. Jest to akt użycia masterhead w większym równaniu, które ostatecznie określi jego typ. – ocharles

Powiązane problemy