Haskell:GHC不能推断出类型。刚性类型变量受到类型签名错误的限制 [英] Haskell: GHC cannot deduce type. Rigid type variable bound by the type signature error

查看:105
本文介绍了Haskell:GHC不能推断出类型。刚性类型变量受到类型签名错误的限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



现在我有一个带签名的函数:

  run':: Expr query => RethinkDBHandle  - >查询 - > IO [JSON] 

这是一个数据库查询运行函数。



我将这个函数包装在一个池中(池已经创建并且与问题无关),以简化连接。

  rdb q = withResource pool(\ h  - > run'(use h $ dbtest)q)

基本上,这个函数的签名与上面的run完全一样。

问题是如果我使用没有签名的函数,那么所有好,GHC很高兴搞清楚事情。一旦我指定了签名,它就会停止对某些输入进行处理,抱怨无法推断该类型。



主要有两种输入类型用作查询输入。

  ReQL和表

这两种类型都是 Expr 的实例,所以它们都被GHC接受。



只要我把签名一切停止工作,GHC coplains关于不能推断类型,并给我由类型签名绑定的刚性类型变量错误。如果我使签名更具体,比如 ReQL 而不是 Expr a ,那么很明显它会停止接受输入,反之亦然。将输入指定为 Expr a ,其中 ReQL 是上述错误的例子。所有放在一起的签名都可以正常工作。



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



我不知道我是否应该使问题更通用或更具体,但如果它有帮助,这是图书馆与所有类型和实例来帮助建议。



Rethink DB



更新 $ b

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

  main = do 
pool< - createPool(connectlocalhost28015 Nothing)close 1 300 5
让rdb q = with资源池(\ h - > run'(使用h $ dbtest)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 $ tablemytable
text $ T.pack $ show j

这是完整的错误列表

  Main。 hs:19:17:
由于使用`basal'
而没有实例(Expr q0)类型变量`q0'不明确
可能的修正:添加修复的类型签名
实例
实例Expr() - 在`Database.RethinkDB.ReQL'中定义
实例(Expr a,Expr b)= > Expr(a,b)
- 在`Database.RethinkDB.ReQL'中定义
实例(Expr a,Expr b,Expr c)=> Expr(a,b,c)
- 在`Database.RethinkDB.ReQL'中定义
...加上24个
在`($)'的第二个参数中,基本rdb'
在'do'块的标记中:scotty 3000 $ basal rdb
在表达式中:
do {pool< - createPool
(connectlocalhost 28015无)close 1 300 5;
让rdb q = withResource pool(\ h - > ...);
scotty 3000 $ basal rdb}

Main.hs:26:19:
无法从上下文推断(q〜Table)
(Expr q)
绑定
的类型签名showJson :: Expr q => (q - > IO [JSON]) - > ActionM()
在Main.hs:24:13-52
`q'是由$ b $绑定的刚性类型变量
的类型签名showJson :: Expr q => ; (q - > IO [JSON]) - > ActionM()
在Main.hs:24:13
在`table'调用的返回类型中
在`($)'的第二个参数中,即`tablemytable ''
在`($)'的第二个参数中,即`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 的积极性有关c $ c>。由于写这个函数的方式, q 更像输出参数而不是输入参数,实际上,函数创建 > a Table (带 table ),而不是要求太高。函数 Expr q =>表 - > q 。)



现在,很好地导致 basal 有类型

  basal ::(表 - > IO [JSON]) - > ScottyM()

  basal ::(forall q.Expr q => q  - > IO [JSON]) - > ScottyM()

因此导致您的无法推断(q〜Table) 错误。






此时我不确定为什么指定显式类型 rdb 会导致问题,但可能清除这个问题将会阻止问题发生。通常一旦你已经打破了类型系统,很难预测其在其他地方的行为。


I'v seen a couple of posts with a similar subject but they don't really help me to solve my problem. So I dare to repeat.

Now I have a functions with signature:

run' :: Expr query => RethinkDBHandle -> query -> IO [JSON]

this is a database query run function.

I wrap this function in a pool (pool is already created and irrelevant to the question) to simplify connections.

rdb q = withResource pool (\h -> run' (use h $ db "test") q)

Essentially, this function has exact the same signature as the run above.

The problem is that if I use the function without a signature then all is good and GHC is happy figuring things out. As soon as I specify the signature it stops working on certain input complaining about not being able to deduce the type.

There are mainly two input types that are used as query input.

ReQL and Table

Both of those types are instances of Expr so they both accepted by GHC.

As soon as I put the signature everything stops working and GHC coplains about not being able to deduce the type and gives me "rigid type variable bound by the type signature" error. If I make signature more specific like ReQL instead of Expr a, then obveously it stops accepting Table input and visa versa. Specifying input as Expr a, which both ReQL and Table are instances of, stops with the error above. Dropping the signature all together works fine.

So how do I solve this? Dropping the signature feels wrong.

I don't know if I should make the question more generic or more specific but if it helps this is the library with all the types and instances to help with an advice.

Rethink DB

UPDATE

As requested, this is the full code listing producing the error.

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

And this is the full error listing

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

Thank you

解决方案

Reading the error messages it seems the first problem is that the type you specify for showJson is wrong.

As r is being applied directly to table which is table :: String -> Table its type is not

r :: Expr q => q -> IO [JSON]

but instead either

r :: Table -> IO [JSON]

or (using RankNTypes)

r :: forall q . Expr q => q -> IO [JSON]

The first is simpler and more direct while the second is probably closer to your intended meaning---it can be read as "fromJson takes an input which it demands uses only the Expr interface on its argument" instead of "fromJson takes any kind of input which happens to use an Expr instantiated type as its argument". For instance, with the type you've given

fromJson (undefined :: Query -> IO [JSON])

would unify as well... but clearly that's now how r is being used in the function body.

(In particular, it has to do with the positivity of the parameter q. Due to the way this function is written, q acts more like an output argument than an input argument. Indeed, the function creates a Table (with table) instead of demanding one. The argument you've written thus implies that we have a function Expr q => Table -> q.)

Now, this specificity of type transmits upward as well causing basal to have the type

basal :: (Table -> IO [JSON]) -> ScottyM ()

or

basal :: (forall q . Expr q => q -> IO [JSON]) -> ScottyM ()

and thus leading to your Cannot deduce (q ~ Table) error.


At this point I can't be sure why stating an explicit type for rdb would lead to issues, but it may be that clearing this one will stop problems from occurring there. Usually once you've already broken the type system it's very hard to predict its behavior in other locations.

这篇关于Haskell:GHC不能推断出类型。刚性类型变量受到类型签名错误的限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆