2011-11-12 13 views
50

Tôi có một lược đồ có 6 loại thực thể khác nhau, nhưng tất cả chúng đều có nhiều điểm chung. Tôi nghĩ rằng tôi có thể có thể trừu tượng rất nhiều tính phổ biến này ra ở cấp độ loại, nhưng tôi đã nhấn một vấn đề với HaskellDB và các trường hợp trùng lặp. Đây là mã tôi đã bắt đầu, hoạt động tốt:Làm cách nào để sử dụng HaskellDB với các trường đa hình? (Các vấn đề với các trường hợp trùng lặp)

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 

Điều này làm việc tốt, nhưng branch quá cụ thể. Những gì tôi thực sự muốn thể hiện như sau:

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

Tuy nhiên, với sự thay đổi này, tôi nhận được lỗi sau:

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 

tôi đã cố gắng một cách mù quáng ném -XOverlappingInstances-XIncoherentInstances lúc này, nhưng điều đó không giúp đỡ (và tôi muốn thực sự hiểu tại sao thay thế một loại bê tông với một biến kiểu gây ra vấn đề này).

Bất kỳ trợ giúp và lời khuyên nào sẽ được đánh giá cao!

+0

Theo hướng dẫn sử dụng http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#undecidable-instances IncoherentInstances cần phải được thêm vào Database.HaskellDB. HDBRec có hiệu lực. –

+0

Cụ thể: Sự sẵn sàng để được chồng chéo hoặc không mạch lạc là một thuộc tính của bản thân khai báo cá thể, được kiểm soát bởi sự hiện diện hoặc các cờ -XOverlappingInstances và -XIncoherentInstances khi mô-đun đó đang được xác định. –

Trả lời

2

Với tuổi của câu hỏi này, nó có lẽ là quá muộn của một câu trả lời để thực hiện bất kỳ sự khác biệt cho bạn, nhưng có lẽ nếu một số người khác đi kèm cùng với một vấn đề tương tự ...

Nó đi xuống đến thực tế là không thể suy ra rằng bạn muốn entity để tham chiếu đến Book khi branch được sử dụng trong masterHead. Một phần của thông báo lỗi mà đọc

The choice depends on the instantiation of `entity0'

cho bạn biết nơi bạn cần phải loại bỏ sự mơ hồ, cụ thể mà bạn cần phải cung cấp thêm thông tin về những gì entity0 nên. Bạn có thể đưa ra một số chú thích kiểu để giúp mọi thứ.

Thứ nhất, xác định branch như

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

và sau đó thay đổi masterHead để đọc

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 

Lưu ý các chú thích kiểu áp dụng cho branch: branch :: BranchTable Book phục vụ để loại bỏ sự mơ hồ đó đã gây ra lỗi loại .

Để làm masterHead áp dụng đối với bất cứ điều gì với một lĩnh vực Revision e trong nó, bạn có thể sử dụng định nghĩa này:

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) 

Đối số et là cần thiết để xác định những loại e nên và chỉ có thể undefined gán cho loại đúng như trong

masterHead bookRevision (undefined :: Book) 

mà tạo ra các 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 

điều này yêu cầu FlexibleContexts mặc dù, nhưng nó có thể được áp dụng cho mô-đun của người hỏi mà không biên dịch lại HaskellDB.

+0

Không quá muộn! Điều này chỉ đơn giản là một số công việc sở thích thú vị, do đó, không có thời hạn :) Tuy nhiên, điều này dường như không giải quyết được vấn đề. Tôi không muốn định nghĩa masterHead về mặt sách vì nó có ý định đa hình trên kiểu thực thể. Có các thực thể khác cũng có masterHead (nhà xuất bản, ấn bản). Điểm mấu chốt của vấn đề này là các kiểu thực thể này được định nghĩa bên ngoài gói với masterHead, vì các công cụ masterHead được cung cấp từ một khung công tác nội bộ cơ bản. – ocharles

+0

@ocharles, vì vậy bạn muốn 'masterHead' lấy tham số của bảng cơ sở thay vì sử dụng' bookRevision' cụ thể? –

+0

Ok, nhìn lại - yea, masterHead cũng là tham số vì những loại khác cũng có ý tưởng 'masterHead'. Tôi nghĩ rằng những gì tôi cũng muốn là làm điều này mà không cần phải vượt qua các loại bổ sung. Đó là hành động của việc sử dụng masterHead trong một phương trình lớn hơn mà cuối cùng sẽ xác định loại hình của nó. – ocharles