2016-03-02 5 views
9

Ich habe zwei GADTs, die ich verwende, um eine SQL EDSL zu modellieren. Um den Client sauber und einfach gegenüber dem API zu halten, möchte ich OverloadedStrings verwenden, um String-Literale in eine Column Selection zu konvertieren.So lösen Sie die Mehrdeutigkeit in meinen GADTs

Daher können Sie einfach

select ["a", "b"] $ from tbl 

statt für Abfragen

select [Column "a", Column "b"] $ from tbl 

Das Problem ist, dass wählen Sie ermöglicht für beide Column Selection s und Reduction s zu ermöglichen, geben Sie die Aggregationen auszuführen.

mean :: Column Selection -> Column Reduction 

select :: [Column a] -> Query b -> Query Selection 
select [mean "a"] $ from tbl 

und somit sind die Saiten in diesem Zusammenhang von [Column a] zweideutig. Aber select [mean "a"] $ from tbl ist gültig, da mean den erforderlichen Kontext bereitstellt, um zu folgern, dass das Zeichenfolgenliteral eine Spaltenauswahl ist.

Kann jemand einen Ausweg aus dieser Unordnung empfehlen?

Mein aktueller Code (irrelevant Instanzen weggelassen)

{-# LANGUAGE 
    GADTs 
    , RankNTypes 
    , DataKinds 
    , TypeFamilies 
    , FlexibleContexts 
    , FlexibleInstances 
    , OverloadedStrings #-} 

data Sz = Selection | Reduction deriving Show 
data Schema = Schema{name :: Maybe String, spec :: [Column Selection]} 

type family ColOp (a :: Sz) (b :: Sz) where 
    ColOp Selection Selection = Selection 
    ColOp Selection Reduction = Selection 
    ColOp Reduction Selection = Selection 
    ColOp Reduction Reduction = Reduction 

data Column (a :: Sz) where 
    Column :: String -> Column Selection 
    Assign :: String -> Column a -> Column a 
    FKey :: String -> Schema -> Column Selection 
    BinExpr :: BinOp -> Column a -> Column b -> Column (ColOp a b) 
    LogExpr :: LogOp -> Column a -> Column b -> Column Selection 
    AggExpr :: AggOp -> Column Selection -> Column Reduction 

instance IsString (Column Selection) where 
    fromString s = Column s 

data Query (a :: Sz) where 
    Table :: Schema -> Query Selection 
    Select :: [Column a] -> Query b -> Query Selection 
    Update :: [Column a] -> Query b -> Query Selection 
    Where :: [Column Selection] -> Query Selection -> Query Selection 
    Group :: [Column Selection] -> Query Selection -> Query Reduction 

Ich würde auch die folgende Signatur mag nicht für Select/Update machen:

[Column Selection] -> Query Reduction -> Query Selection 

Aber das ist eine ganz andere Dose von Würmern ...

+1

'mittlere" a "' typechecks ganz gut mit diesem Code, und der abgeleitete Typ des '" a "' ist genau 'Spalte' Selection '. Dann ist der Typ von 'Select [mean" a "]' 'Query b -> Query 'Selection'. Wenn etwas nicht funktioniert, bitte genau angeben, welcher Ausdruck die Mehrdeutigkeit verursacht und was der tatsächliche Fehler ist. Sie haben '' '' '' '' '' '' '' '' '' '' tbl nicht definiert, ist der Fehler möglicherweise mit diesen Funktionen verbunden. – user2407038

+0

rechts, aber 'wählen [" a "] $ from tbl' does * not * typecheck. –

+0

'from = Table' und' tbl = Schema {name = Nur "tbl", spec = [Spalte "a", Spalte "b"]} ' –

Antwort

6

Der Compiler ist korrekt, um Ihnen einen mehrdeutigen Typfehler für zu geben Select ["a"] - die IsString (Column Selection) Instanz kann ausgewählt werden nur wenn a priori das Argument zu Column bekannt ist Selection. Dies ist genau das beabsichtigte Verhalten.

Was Sie wollen, ist die folgende:

instance (x ~ Selection) => IsString (Column x) where 
    fromString = Column 

Dies ist der Compiler ermöglicht, zu folgern, dass "x" :: Column _ tatsächlich "x" :: Column Selection sein muss, im Gegensatz zu erfordern es.

Select [mean "a"] ist eine völlig andere Situation - da mean :: Column Selection -> Column Reduction, der Compiler weiß, bevor Instanz Auswahl geschieht, dass "a" :: Column Selection, weil die Art der mean Kräfte dies der Fall zu sein.

Verwandte Themen