让我们考虑以下示例:
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的类型推理器为我做这个工作
答案 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
的结果