I have two GADTs I am using to model a SQL EDSL. To keep the client facing api clean and simple I want to use OverloadedStrings to cast string literals to a Column Selection. 
Therefore you can simply type
select ["a", "b"] $ from tbl
instead of
select [Column "a", Column "b"] $ from tbl
The problem is that select allows for both Column Selections and Reductions
to allow for queries that perform aggregations. 
mean :: Column Selection -> Column Reduction
select :: [Column a] -> Query b -> Query Selection
select [mean "a"] $ from tbl
and thus the strings are ambiguous in this context of [Column a].
But select [mean "a"] $ from tbl is valid since mean provides the necessary context to infer that the string literal is a Column Selection. 
Can anyone recommend a way out of this mess?
My current code below (irrelevant instances omitted)
{-# 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
I would also like to make the following signature fail for Select/Update:
[Column Selection] -> Query Reduction -> Query Selection
But that's a whole other can of worms...
The compiler is correct to give you an ambiguous type error for Select ["a"] - the IsString (Column Selection) instance can be chosen only if a priori the argument to Column is known to be Selection. This is exactly the intended behaviour.
What you want is the following:
instance (x ~ Selection) => IsString (Column x) where
    fromString = Column 
This will allow the compiler to infer that "x" :: Column _ must actually be "x" :: Column Selection, as opposed to requiring it. 
Select [mean "a"] is a completely different situation - since mean :: Column Selection -> Column Reduction, the compiler knows, before instance selection happens, that "a" :: Column Selection, because the type of mean forces this to be the case. 
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With