不幸的是,这实际上是不可能的: 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 |]
.
您可能还对广义箭头扩展感兴趣,尽管对于您的目的而言,它可能是矫枉过正(而且过于实验性)。