在类型类中键入注释'默认值会导致"无法推断"类型错误

bkl*_*lin 4 haskell type-inference typeclass

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

class A a where
  foo :: a
class A a => B a where
  bar :: a
  bar = (foo :: a)
Run Code Online (Sandbox Code Playgroud)

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

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

GHC似乎不相信类型B的定义中的所有a都是相同的.任何人都可以解释它的推理究竟是什么?

删除第5行中的类型注释可以避免问题,但我仍然想了解这里发生了什么......

Ste*_*ans 11

你应该确实摆脱类型注释.类型变量不在Haskell中作用域,所以(foo :: a).被解释为"具有foo生产类型的值a用于任何类型的a",这是无法做到的foo,只会产生这些类型的值a是在类A.

换句话说,您的声明B等同于

class A a => B a where
  bar :: a
  bar = (foo :: c)
Run Code Online (Sandbox Code Playgroud)

也就是说,在使用类型变量a和声明中的其他用法之间没有任何关联.

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

class A a => B a where
  bar :: a
  bar = foo
Run Code Online (Sandbox Code Playgroud)

现在,编译器可以确定要调用foo的类型a,即您在签名中编写的类型bar以及类声明头部中显示的类型.

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

{-# LANGUAGE ScopedTypeVariables #-}
class A a where
  foo :: a
class A a => B a where
  bar :: a
  bar = (foo :: a)
Run Code Online (Sandbox Code Playgroud)