我看过一些有类似主题的帖子,但它们并没有真正帮助我解决我的问题.所以我敢重复一遍.
现在我有一个带签名的函数:
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都是其实例)将停止并显示上述错误.将签名全部放在一起工作正常.
那么我该如何解决这个问题呢?丢弃签名感觉不对.
我不知道我是否应该使问题更通用或更具体,但如果它有帮助,这是具有所有类型和实例的库来帮助提供建议.
UPDATE
根据要求,这是产生错误的完整代码清单.
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"'
谢谢
最佳答案 阅读错误消息似乎第一个问题是你为showJson指定的类型是错误的.
因为r直接应用于table :: String – >这个表.表的类型不是
r :: Expr q => q -> IO [JSON]
但相反
r :: Table -> IO [JSON]
或(使用RankNTypes)
r :: forall q . Expr q => q -> IO [JSON]
第一个更简单,更直接,而第二个可能更接近你的意图 – 它可以被读作“fromJson接受一个输入,它要求只在其参数上使用Expr接口”而不是“fromJson接受任何一种输入恰好使用Expr实例化类型作为其参数“.例如,您提供的类型
fromJson (undefined :: Query -> IO [JSON])
也会统一…但显然现在如何在函数体中使用r.
(特别是,它与参数q的积极性有关.由于写入此函数的方式,q更像输出参数而不是输入参数.实际上,函数创建一个表(带表)而不是你写的这个论点意味着我们有一个函数Expr q => Table – > q.)
现在,这种类型的特异性向上传递也导致基础具有类型
basal :: (Table -> IO [JSON]) -> ScottyM ()
要么
basal :: (forall q . Expr q => q -> IO [JSON]) -> ScottyM ()
从而导致你无法推断(q~Table)错误.
在这一点上,我不能确定为什么说明rdb的显式类型会导致问题,但是清除这个问题可能会阻止问题发生在那里.通常一旦你已经破坏了类型系统,就很难预测其在其他地方的行为.