添加未使用的实例可修复类型错误

时间:2017-11-08 04:50:30

标签: haskell ghc typeclass

考虑以下代码:

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

module Foo where

class Foo a

class SomeClass a
instance {-# OVERLAPPABLE #-} (Foo a) => SomeClass a

bar :: (SomeClass a) => a -> Int
bar = const 0

foo :: (SomeClass a) => a -> Int
foo t = let x = bar t in x

此处,foo调用bar,并且应该能够在其上下文中使用SomeClass约束来执行此操作。相反,GHC假定它必须使用Foo a => SomeClass a实例:

Foo.hs:16:17:
    Could not deduce (Foo a) arising from a use of ‘bar’
    from the context (SomeClass a)
      bound by the type signature for foo :: SomeClass a => a -> Int
      at Foo.hs:15:8-32
    Possible fix:
      add (Foo a) to the context of
        the inferred type of x :: Int
        or the type signature for foo :: SomeClass a => a -> Int
    In the expression: bar t
    In an equation for ‘x’: x = bar t
    In the expression: let x = bar t in x

有两种方法可以解决这个问题:

  1. foo中,将let x = bar t in x更改为bar t
  2. 将行instance SomeClass Int附加到我的程序
  3. 这里发生了什么?为什么会出现此问题,为什么这些修复工作正常?

    这个例子当然是由我的实际问题简化的。我在Cubix多语言转换框架工作期间遇到过这个问题(arxiv.org/pdf/1707.04600)。

    我的实际问题涉及具有约束InjF f IdentL FunctionExpL的函数(&#34; f是一种语言,其中标识符可用于表示函数调用中的函数&#34;)。我有一个(可重叠的)实例(FunctionIdent :<: f) => InjF f IdentL FunctionExpL,这是typechecker抓住的,给我一个虚假的Could not deduce FunctionIdent :<: f错误。

    即使在特定InjF Foo IdentL FunctionExpL的范围内存在Foo实例,此错误仍然存​​在,因此左下方的答案预测其他实例应该解决问题,不是全文。

1 个答案:

答案 0 :(得分:3)

原因是编译器尝试使x尽可能通用:它希望它是(SomeClass a) => Int(注意如果你自己写出来,这将是一个模糊的类型)。防止这种奇怪的本地类型的一种方法是启用-XMonoLocalBinds,但我不会真的推荐它。

现在,编译器继续进行类型检查。那时,范围内只有一个instance SomeClass,即全能(Foo a) => SomeClass a,所以没有歧义。 (原则上,Haskell完全禁止实例解析中的歧义; OVERLAPPABLE颠覆了这一点,但只有在需要时才会跳转到操作,就像你有一个额外的instance SomeClass Int一样。)因此,编译器立即提交到该实例,因此消除(SomeClass a) c的类型检查。如果您确实希望将类约束替换为实例的约束,则必须执行此操作。在给定的示例中,这似乎无用,但是当您拥有表单实例时,它实际上是至关重要的

instance Bar a => SomeClass (Maybe a)

...这比你的代码更合理,因为可以表示为超类约束,并且完全可以没有任何重叠。如果编译器在这些情况下没有将约束降低到Bar a,那么它实际上永远无法解析Maybe类型。

结论:避免重叠实例;如果可能的话,通过超类声明来表达类关系,否则将约束重新化为GADT(这很笨拙,但可以精确控制将使用哪个约束)。