5

我正在研究使用 monad 理解来表示 SQL 查询,并生成适当的 SQL。乍一看,这不是问题,似乎很合适。但是我必须限制类型,这些类型只能将单子形成为产品,没有总和,我想不出一种方法来放置这样的约束。

我想使用类型检查器来确保只能使用 SQL 中可表示的类型。

我想,我可以使用模板 haskell 来派生正确的实例,如果类型不适合,则拒绝派生,但我更希望在类型级别完成。由于我的无知,我引入错误的机会较少。

我怎么能这样做?如果是,请您推荐一些阅读和/或代码示例。

编辑:谢谢,我有一些好的路径可以遵循,需要更多阅读:) 这里是一个长周末。

4

1 回答 1

8

不幸的是,这实际上是不可能的: aMonad必须是完全多态的。这与您不能制作Set单子(Ord约束)的原因相同。

如果你只能处理让结果类型满足约束,那么你可以有runSQL :: (Product a) => SQL a -> IO a,或类似的。在这种情况下,只需使用 Template Haskell 派生适当的实例即可,或者使用新的GHC Generics;普通的 Haskell 无法确定一个类型是否仅由产品组成。

但我怀疑您需要访问一元计算的整个结构,才能将其转换为 SQL。不幸的是,monad 并没有很好地做到这一点,因为它们与任意的 Haskell 函数连接在一起,你无法“查看内部”。箭头更近,可以让你做更多的静态分析,但仍然有那个讨厌arr的地方,让你再次潜入任意 Haskell 函数。

做这样的事情最可行的选择可能是编写一个模板 Haskell 拼接器来解析你想要的语法;您可以说$(sql [| [ (a,b) | a <- table1, b <- table2 |])sql在编译时将 AST 转换为相应的 SQL 如果该语法太难看,您可以编写使用带有haskell-src-meta的准引用器,它看起来像[sql| (a, b) | a <- table1, b <- table2 |].

您可能还对广义箭头扩展感兴趣,尽管对于您的目的而言,它可能是矫枉过正(而且过于实验性)。

于 2012-04-05T15:36:57.780 回答