0

为了减少将 Haxl 与关系数据库一起使用所需的样板文件的目标,我试图通过 Persistent 将原始 SQL 请求的结果打包为存在量化类型。但是类型检查器不允许它:

data SomeRawSql where
  SomeRawSql :: forall b. RawSql b => [b] -> SomeRawSql

packedVal = let res = runDB $ rawSql "SELECT * FROM ..." [toPersistValue (pack "ABC")]
             in fmap SomeRawSql res

这会导致 fmap 出现类型错误:Ambiguous type variable ‘b0’ arising from a use of ‘SomeRawSql’ prevents the constraint ‘(RawSql b0)’ from being solved.

持久化 rawSql 的类型是:

rawSql :: (RawSql a, MonadIO m)
       => Text             -- ^ SQL statement, possibly with placeholders.
       -> [PersistValue]   -- ^ Values to fill the placeholders.
       -> ReaderT SqlBackend m [a]

runDB是一个辅助函数,它连接到数据库并返回IO [a]. 根据 rawSql 的定义,我希望能满足 RawSql 约束。我不明白为什么会出现这个错误。

4

1 回答 1

3

rawSql普遍量化的。这意味着,它不会“RawSql从数据库中提取实例”,这将是存在类型SomeRawSql所表达的。相反,只要它们有一个RawSql实例,它就可以从数据库中提取值。这是调用者选择的类型。

您还可以将通用量化包装在无参数类型中:

data SomeRawSql where
  SomeRawSql :: (forall b. RawSql b => [b]) -> SomeRawSql

但我认为这不明智,它只是减轻了选择类型的负担。参数化是一件好事,它使您可以实际跟踪哪些类型在哪里。不要无故绕过它!

一个完全不同的主题是,如果你想检索一个你真的不知道其类型的值。这不包括在内rawSql,您需要自己使用Dynamic.

于 2018-01-16T10:54:38.103 回答