haskell - 强制使用幻像类型的不明确实例

标签 haskell

我正在使用mysql-simple,并且我尝试使用幻像类型以避免必须使用显式类型签名。

假设我正在尝试执行以下查询SELECT Firstname, Lastname FROM users

我会尝试这样的事情:

{-# LANGUAGE OverloadedStrings #-}
import Database.MySQL.Simple

myQuery :: Query
myQuery = "SELECT firstname, lastname FROM users"

main = do
    conn <-connect defaultConnectInfo
    rows <- queryT conn myQuery
    mapM_ print rows

这不起作用,因为编译器无法推断出的类型。解决方案是添加如下类型签名:

{-# LANGUAGE OverloadedStrings #-}
import Database.MySQL.Simple

myQuery :: Query
myQuery = "SELECT firstname, lastname FROM users"

main = do
    conn <-connect defaultConnectInfo
    rows <- queryT conn myQuery
    mapM_ print (rows :: [(String, String)]) ------<< Here

编译器推断出每一行都是(String, String)并且一切正常。 然而,这个解决方案并不令人满意,因为如果我修改 myQuery 我需要修改 rows 类型签名。而且,这是一个简化的示例。在实际代码中,查询来自查询组合器(它保存行类型),因此无法对行类型进行硬编码。

我尝试使用幻像类型来使用类型化查询

{-# LANGUAGE OverloadedStrings #-}
import Database.MySQL.Simple


data QueryT a = QueryT Query  ---------------<< Phantom type
queryT :: Connection -> QueryT a -> IO [a]
queryT conn (QueryT q) = query_ conn q


myQuery :: QueryT (String, String) ----------<< Query holding it's row type
myQuery = QueryT $ "SELECT firstname, lastname FROM users"

main = do
    conn <-connect defaultConnectInfo
    rows <- queryT conn myQuery
    mapM_ print rows

这行不通。我收到以下消息:

stack.hs:7:26:
No instance for (Database.MySQL.Simple.QueryResults.QueryResults a)
  arising from a use of `query_'
Possible fix:
  add (Database.MySQL.Simple.QueryResults.QueryResults
         a) to the context of
    the type signature for queryT :: Connection -> QueryT a -> IO [a]
In the expression: query_ conn q
In an equation for `queryT': queryT conn (QueryT q) = query_ conn q

如果我在 queryT 类型签名中将幻像类型替换为 (String, String)

queryT :: Connection -> QueryT a -> IO [(String, String)]

一切又恢复正常了。那么区别是什么呢 ? 为什么类型推断无法推断出 rows 的类型为 [(String, String)]

(我尝试过函数依赖和类型族,但这似乎也没有帮助)。

最佳答案

问题不在于为您调用 queryT 的行类型推断 (String, String);就可以很好地推断出。

问题在于编译 queryT 本身;这是 a 中的多态性,因此编译器不应该推断 (String, String),它应该编译适用于 < em>任何类型a。但是 queryT 是通过调用 query_ 来获取结果的,而 query_ 根本无法对任何类型起作用,只能对QueryResult 类型类。

但是您不希望能够在声称生成 Either (IO [a -> Int]) (Maybe Void) 的查询上运行 queryT 作为行类型超过 query_ 希望将其作为可能的行类型,因此解决方案是限制 queryT 对幻像类型位于 QueryResult< 中的查询进行操作 也是:

queryT :: QueryResult a => Connection -> QueryT a -> IO [a]

这正是建议的“可能的修复”的含义,即将 QueryResult a 添加到 queryT 的上下文中。类型签名的“上下文”是 => 之前的所有内容,您可以在其中编写对所涉及的类型变量的约束。

关于haskell - 强制使用幻像类型的不明确实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23727582/

相关文章:

haskell - 尝试使用 Aeson 解码时出现莫名其妙的错误

haskell - 调用堆栈管理

layout - 在 Haskell 中,对于递归函数使用守卫比模式更好吗?

haskell - Windows 上的 regex-pcre

haskell - monad 中的 "run"是什么意思?

haskell - Yesod数据库持久记录访问

haskell - 创建相同类型类但不同类型的值列表

html - 如何在 blaze-html 中渲染 blaze-svg 标记

haskell - Haskell monad 不强制执行的分类单子(monad)的身份是什么?

sql - 在 Groundhog Haskell 中通过投影键选择行的理想方法是什么