我见过几篇有类似主题的帖子,但他们并没有真正帮助我解决我的问题。所以我敢重复。
现在我有一个签名函数:
run' :: Expr query => RethinkDBHandle -> query -> IO [JSON]
这是一个数据库查询运行功能。
我将此函数包装在池中(池已经创建且与问题无关)以简化连接。
rdb q = withResource pool (\h -> run' (use h $ db "test") q)
基本上,此函数与上面的运行具有完全相同的签名。
问题在于,如果我使用没有签名的功能,那么一切都很好,GHC很乐意解决问题。一旦我指定签名,它就会停止处理某些输入,抱怨无法推断出类型。
主要有两种输入类型用作查询输入。
ReQL and Table
这两种类型都是Expr
的实例,因此它们都被GHC接受。
一旦我把签名一切都停止了工作,GHC就不能推断出类型并给我"刚性类型变量绑定类型签名"错误。如果我使签名更加具体,例如ReQL
而不是Expr a
,那么就会停止接受Table
输入,反之亦然。将输入Expr a
指定为ReQL
和Table
的实例,将停止并显示上述错误。将签名全部放在一起工作正常。
那么我该如何解决这个问题呢?丢弃签名感觉不对。
我不知道我是否应该使问题更通用或更具体,但如果有帮助,这就是包含所有类型和实例的图书馆,以帮助提供建议。
更新
根据要求,这是产生错误的完整代码清单。
main = do
pool <- createPool (connect "localhost" 28015 Nothing) close 1 300 5
let rdb q = withResource pool (\h -> run' (use h $ db "test") q)
scotty 3000 $ basal rdb
basal :: Expr q => (q -> IO [JSON]) -> ScottyM ()
basal r = get "/json" $ showJson r
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
showJson r = do
j <- lift $ r $ table "mytable"
text $ T.pack $ show j
这是完整的错误列表
Main.hs:19:17:
No instance for (Expr q0) arising from a use of `basal'
The type variable `q0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Expr () -- Defined in `Database.RethinkDB.ReQL'
instance (Expr a, Expr b) => Expr (a, b)
-- Defined in `Database.RethinkDB.ReQL'
instance (Expr a, Expr b, Expr c) => Expr (a, b, c)
-- Defined in `Database.RethinkDB.ReQL'
...plus 24 others
In the second argument of `($)', namely `basal rdb'
In a stmt of a 'do' block: scotty 3000 $ basal rdb
In the expression:
do { pool <- createPool
(connect "localhost" 28015 Nothing) close 1 300 5;
let rdb q = withResource pool (\ h -> ...);
scotty 3000 $ basal rdb }
Main.hs:26:19:
Could not deduce (q ~ Table)
from the context (Expr q)
bound by the type signature for
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
at Main.hs:24:13-52
`q' is a rigid type variable bound by
the type signature for
showJson :: Expr q => (q -> IO [JSON]) -> ActionM ()
at Main.hs:24:13
In the return type of a call of `table'
In the second argument of `($)', namely `table "mytable"'
In the second argument of `($)', namely `r $ table "mytable"'
谢谢
答案 0 :(得分:2)
阅读错误消息似乎第一个问题是您为showJson
指定的类型是错误的。
由于r
直接应用于table
table :: String -> Table
,其类型不
r :: Expr q => q -> IO [JSON]
但是要么
r :: Table -> IO [JSON]
或(使用RankNTypes
)
r :: forall q . Expr q => q -> IO [JSON]
第一个更简单,更直接,而第二个更接近你的预期含义 - 它可以被读作&#34; fromJson
接受一个输入,它要求只使用{{1} }参数接口&#34;代替&#34; Expr
采用任何类型的输入,恰好使用fromJson
实例化类型作为其参数&#34;。例如,使用您提供的类型
Expr
也会统一...但显然现在fromJson (undefined :: Query -> IO [JSON])
在函数体中的使用方式。
(特别是,它与参数r
的积极性有关。由于写入此函数的方式,q
更像是输出参数而不是输入参数。实际上,函数创建一个q
(带有Table
),而不是要求一个。你所写的论据暗示我们有一个函数table
。 )
现在,这种类型的特殊性也向上传输,导致Expr q => Table -> q
具有类型
basal
或
basal :: (Table -> IO [JSON]) -> ScottyM ()
因而导致basal :: (forall q . Expr q => q -> IO [JSON]) -> ScottyM ()
错误。
此时我无法确定为什么说明Cannot deduce (q ~ Table)
的明确类型会导致问题,但清除此问题可能会阻止问题发生在那里。通常,一旦你已经破坏了类型系统,就很难预测其在其他地方的行为。