Haskell中不完整的隐式类型推断

时间:2013-07-15 15:42:21

标签: haskell types overloading type-inference typeclass

让我们考虑以下示例:

data A = A{x::Int} deriving(Show)

instance Func_f (A -> String) where
    f _ = "ala"

class Func_f a where
    f :: a

main :: IO ()
main = do 
    let 
        a = A 5
        x = f a 
    print 5

使用ghc -XFlexibleInstances main.hs

编译

(我已尝试-XExtendedDefaultRules,但没有任何进展)

为什么在编译时会出现错误?:

main.hs:25:21:
    No instance for (Func_f (A -> t0)) arising from a use of `f'
    The type variable `t0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there is a potential instance available:
      instance Func_f (A -> String) -- Defined at main.hs:7:10
    Possible fix: add an instance declaration for (Func_f (A -> t0))
    In the expression: f a
    In an equation for `x': x = f a
    In the expression:
      do { let a = A 5
               x = f a;
           print 5 }

Func_f只有一个实例,因此Haskell应该能够知道x = f a的结果。您可以通过手动提供类型来修复错误,如下所示:x = f a :: String,但这不适合我的情况,因为我正在生成Haskell代码,我希望Haskell的类型推理器为我做这个工作

2 个答案:

答案 0 :(得分:13)

你正在遇到open world assumption。基本思想是GHC总是假设您可以为代码添加更多类实例。此外,您无法控制在模块之间导出和导入实例的方式。所以依靠只有一个特定类的一个实例是行不通的,会导致奇怪的错误。

基本上,没有什么能阻止你 - 或其他任何人 - 因为写下另一个例子:

 instance Func_f (A -> Int) where
   f _ = 10

然后就不可能在你的代码中弄清楚你想要哪一个。这可能导致您的代码仅仅因为链接到另一个模块而中断!

但是,如果你实际使用了这个值,很可能它的类型受到其他参数的约束而且模糊性会消失。例如,以下工作:

main :: IO ()
main = do 
  let a = A 5
      x = f a
  putStr x

基本上,这是其中一种情况(类似于read . show),由于GHC如何处理类型类实例,因此类型签名根本不可避免。

答案 1 :(得分:4)

  

Func_f只有一个实例,所以Haskell应该能够知道x = f a

的结果

这违反了the open world assumption.