gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 17:03:06 24 4
gpt4 key购买 nike

我正在使用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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com