【问题标题】:Type annotation in a typeclass' default value causes a "could not deduce" type error类型类的默认值中的类型注释会导致“无法推断”类型错误
【发布时间】:2012-04-20 09:53:27
【问题描述】:

这是一个初学者的问题,但我无法在任何地方找到任何答案。
以下代码:

class A a where
  foo :: a
class A a => B a where
  bar :: a
  bar = (foo :: a)

无法在 GHC 中编译,并显示错误消息:

Could not deduce (A a1) arising from a use of `foo'
from the context (B a)
  bound by the class declaration for `B'
...

GHC 似乎不相信 typeclass B 定义中的所有 a 都是相同的。谁能解释一下它的推理路线到底是什么?

去掉第 5 行的类型注解当然可以避免这个问题,但我还是想了解这里发生了什么……

【问题讨论】:

    标签: haskell type-inference typeclass


    【解决方案1】:

    您确实应该摆脱类型注释。类型变量在 Haskell 中没有作用域,所以 (foo :: a)。被解释为“让foo 为任何类型a 生成a 类型的值”,这是无法完成的,因为foo 只会生成a 类中的A 类型的值.

    换句话说,你的B声明相当于

    class A a => B a where
      bar :: a
      bar = (foo :: c)
    

    也就是说,你对类型变量a的使用与声明中的其他使用没有任何联系。

    删除显式注释可以解决您的问题:

    class A a => B a where
      bar :: a
      bar = foo
    

    现在,编译器可以确定您要调用 foo 的类型,即您在 bar 的签名中写入的类型 a 并出现在类声明的头部。

    Glasgow Haskell 编译器 (GHC) 带有一个允许范围类型变量的扩展。启用该扩展后,您的片段将像您最初预期的那样进行类型检查:

    {-# LANGUAGE ScopedTypeVariables #-}
    class A a where
      foo :: a
    class A a => B a where
      bar :: a
      bar = (foo :: a)
    

    【讨论】:

    • 非常感谢! XScopedTypeVariables 的文档正是我所需要的。
    • @bklin:如果你认为他的回答足够全面,你应该接受他的回答;)
    【解决方案2】:
    Prelude> :set -XScopedTypeVariables
    Prelude> :{
    Prelude| class A a where
    Prelude|   foo :: a
    Prelude| class A a => B a where
    Prelude|   bar :: a
    Prelude|   bar = (foo :: a)
    Prelude| :}
    Prelude> :t bar
    bar :: B a => a
    Prelude> 
    

    但正如 dblhelox 所说,这里实际上没有必要使用作用域类型变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 2015-04-30
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 2022-08-02
      • 2020-09-01
      相关资源
      最近更新 更多