Haskell:GHC不能推断出类型。由类型签名错误绑定的刚性类型变量

时间:2014-04-01 06:09:59

标签: haskell rethinkdb

我见过几篇有类似主题的帖子,但他们并没有真正帮助我解决我的问题。所以我敢重复。

现在我有一个签名函数:

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指定为ReQLTable的实例,将停止并显示上述错误。将签名全部放在一起工作正常。

那么我该如何解决这个问题呢?丢弃签名感觉不对。

我不知道我是否应该使问题更通用或更具体,但如果有帮助,这就是包含所有类型和实例的图书馆,以帮助提供建议。

Rethink DB

更新

根据要求,这是产生错误的完整代码清单。

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"'

谢谢

1 个答案:

答案 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)的明确类型会导致问题,但清除此问题可能会阻止问题发生在那里。通常,一旦你已经破坏了类型系统,就很难预测其在其他地方的行为。