约束中的不明确类型变量"a0"



我正在尝试从Learn You a Haskell for Great Good!书中浏览YesNo的例子。

我的源代码:

module Main where
main :: IO ()
main = putStrLn ( show (yesno 12) )
class YesNo a where
    yesno :: a -> Bool

instance YesNo Bool where
    yesno b = b
instance YesNo [a] where
    yesno [] = False
    yesno _ = True

instance YesNo Int where
    yesno 0 = False
    yesno _ = True

当我执行这段代码时,出现以下异常:

Ambiguous type variable `a0' in the constraints:
  (YesNo a0) arising from a use of `yesno'
             at /Users/mkhadikov/Projects/personal/haskell/hello-world/yesno.hs:5:25-29
  (Num a0) arising from the literal `12'
           at /Users/mkhadikov/Projects/personal/haskell/hello-world/yesno.hs:5:31-32
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `show', namely `(yesno 12)'
In the first argument of `putStrLn', namely `(show (yesno 12))'
In the expression: putStrLn (show (yesno 12))
你能解释一下这段代码有什么问题吗?

问题是它不知道type 12是什么!它可以是任何带有Num实例的类型:

GHCi> :t 12
12 :: Num a => a

您需要直接指定类型:try putStrLn (show (yesno (12 :: Int))) .

为什么GHC不能选择Int,既然没有其他选择可以工作,你问?好问题。答案是,在Haskell的类型类系统中,添加实例永远不会使现有的正确程序失效或改变它们的行为。(这被称为开放世界假设。)如果它选择了Int,那么如果你加入instance YesNo Integer会发生什么?选择将变得模棱两可,您的程序将崩溃!

因此,当您想要使用具有多态值的类型类时,您必须更精确地指定您所指的类型。这在实践中不应该出现太多,因为通常会有一些周围的上下文来强制类型是你想要的;受此影响的主要是数字字面值

问题是12实际上具有类型Num a => a而不是您期望的Int。如果您添加了显式类型注释,如12 :: Int,它应该可以编译。

我也遇到过同样的问题。

这是一个解决方案,也许不是最好的,但它是有效的:

class YesNo a where
     yesno  ::  a -> Bool

instance YesNo Int where
     yesno 0    =   False
     yesno _    =   True

instance YesNo Integer where
     yesno 0    =   False
     yesno _    =   True

最新更新