2

让我们考虑以下示例:

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 的类型推断器为我完成这项工作。

4

2 回答 2

13

你遇到了开放世界假设。基本思想是 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 如何处理类型类实例而无法避免类型签名的情况之一(类似于)。

于 2013-07-15T15:49:23.987 回答
4

Func_f只有一个实例,所以Haskell应该可以知道x = fa的结果

这违反了开放世界假设。

于 2013-07-15T15:50:28.637 回答