约束中的模糊类型变量`a0'

时间:2011-12-17 16:54:55

标签: haskell

我正在尝试查看YesNo本书中的Learn You a Haskell for Great Good!示例。

这是我的源代码:

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))

你能解释一下这段代码有什么问题吗?

3 个答案:

答案 0 :(得分:38)

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

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

您需要直接指定所需类型:尝试putStrLn (show (yesno (12 :: Int)))

为什么GHC不能选择Int,因为没有其他选择可行,你问?好问题。答案是,使用Haskell的类型类系统,添加实例永远不会使现有的正确程序无效或改变其行为。 (这被称为开放世界假设。)如果确实选择了Int,那么如果添加instance YesNo Integer会发生什么?选择会变得模棱两可,你的程序会破裂!

因此,当您想要使用具有多态值的类型类类型时,您必须更准确地指定您的意思。这在实践中不应该出现太多,因为通常会有一些周围的环境迫使类型成为你想要的类型;它主要是受此影响的数字文字。

答案 1 :(得分:5)

问题是12实际上有Num a => a类型,而不是Int。如果添加显式类型的anotation,例如12 :: Int,则应编译。

答案 2 :(得分:1)

我遇到了同样的问题。

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

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