类型类 101:GHC 也 "eager" 来派生实例?

Typeclasses 101: GHC too "eager" to derive instance?

给定以下代码:

class C a where
  foo :: a -> a

f :: (C a) => a -> a
f = id

p :: (C a) => (a -> a) -> a -> a
p g = foo . g

现在,如果我尝试调用 p f,GHC 会抱怨:

> p f
No instance for (C a0) arising from a use of `p'
In the expression: p f
In an equation for `it': it = p f

我觉得这有点令人惊讶,因为 f 只接受一个必须是类型类 C 的实例的 "a"。原因是什么?

编辑:我知道我没有为 C 定义任何实例,但 "proper" 响应不应该是:

p f :: (C a) => a -> a 

可怕的 monomorphism restriction 正在发生。默认情况下,如果推断类型具有 class 约束,GHC 不允许我们在没有类型注释的情况下拥有顶级值定义。您可以通过

来补救这种情况

a.) 通过将 {-# LANGUAGE NoMonomorphismRestriction #-} 添加到源代码的顶部来关闭限制。

b.) 向受影响的顶级绑定添加类型注释:

foo :: C a => a -> a
foo = p f

c.) 扩展函数定义(如果可能):

foo x = p f x 

当你将一个简单的表达式放入 ghci 时,它基本上是在尝试 print 它,所以

> p f

与在文件中包含以下内容大致相同

main :: IO ()
main = print $ p f

正如您所指出的,p f :: (C a) => a -> a。为了 print $ p f GHC 需要评估 p f。如果不选择要传入的字典,GHC 无法评估具有类型 class 上下文的值。为此,它需要为所有 a 找到一个 C a 实例,该实例不会退出.它还需要为 a -> a 找到一个 Show 实例。无法找到其中任何一个会导致两个错误

No instance for (Show (a -> a)) arising from a use of `print'
No instance for (C a) arising from a use of `p'