Bra*_*gle 9 dsl haskell types gadt
我有两个GADT用于建模SQL EDSL.为了让客户端面对api干净简单,我想OverloadedStrings用来将字符串文字转换为Column Selection.
因此,您只需输入即可
select ["a", "b"] $ from tbl
Run Code Online (Sandbox Code Playgroud)
代替
select [Column "a", Column "b"] $ from tbl
Run Code Online (Sandbox Code Playgroud)
问题是select允许Column Selections和Reductions允许执行聚合的查询.
mean :: Column Selection -> Column Reduction
select :: [Column a] -> Query b -> Query Selection
select [mean "a"] $ from tbl
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,字符串是模糊的[Column a].但是select [mean "a"] $ from tbl有效,因为mean提供了必要的上下文来推断字符串文字是列选择.
任何人都可以推荐摆脱这种混乱的方法吗?
我目前的代码如下(省略了无关的实例)
{-# 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
Run Code Online (Sandbox Code Playgroud)
我也想提出以下签名失败Select/ Update:
[Column Selection] -> Query Reduction -> Query Selection
Run Code Online (Sandbox Code Playgroud)
但那是另外一种蠕虫......
编译器是正确的,给你一个暧昧的错误类型Select ["a"]-的IsString (Column Selection)情况下可以选择只有当一个先验的说法Column是已知的Selection.这正是预期的行为.
你想要的是以下内容:
instance (x ~ Selection) => IsString (Column x) where
fromString = Column
Run Code Online (Sandbox Code Playgroud)
这将允许编译器推断"x" :: Column _必须实际上"x" :: Column Selection,而不是要求它.
Select [mean "a"]是一种完全不同的情况 - 因为mean :: Column Selection -> Column Reduction,在实例选择发生之前,编译器知道"a" :: Column Selection,因为mean强制类型就是这种情况.