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

Woj*_*ilo 2 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
Run Code Online (Sandbox Code Playgroud)

用.编译 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 }
Run Code Online (Sandbox Code Playgroud)

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

Tik*_*vis 13

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

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

 instance Func_f (A -> Int) where
   f _ = 10
Run Code Online (Sandbox Code Playgroud)

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

但是,如果您实际使用了该值,则可能会使其类型受到某些其他参数的约束,并且模糊性将消失.例如,以下工作:

main :: IO ()
main = do 
  let a = A 5
      x = f a
  putStr x
Run Code Online (Sandbox Code Playgroud)

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

  • @danilo是的,当然.只需用`"ala"`替换`fa`即可. (3认同)