我试图通过书中的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
Run Code Online (Sandbox Code Playgroud)
当我执行此代码后发生异常:
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))
Run Code Online (Sandbox Code Playgroud)
你能解释一下这段代码有什么问题吗?
ehi*_*ird 41
问题是它不知道12是什么类型!它可以是具有Num实例的任何类型:
GHCi> :t 12
12 :: Num a => a
Run Code Online (Sandbox Code Playgroud)
您需要直接指定所需的类型:尝试putStrLn (show (yesno (12 :: Int)))
.
为什么GHC不能选择Int,因为没有其他选择可行,你问?好问题.答案是,使用Haskell的类型类系统,添加实例永远不会使现有的正确程序无效或改变其行为.(这被称为开放世界的假设.)如果确实选择了Int,那么如果添加会发生什么instance YesNo Integer
?选择会变得模棱两可,你的程序会破裂!
因此,当您想要使用具有多态值的类型类类型时,您必须更精确地指定您的意思.这在实践中不应该出现太多,因为通常会有一些周围的环境迫使类型成为你想要的类型; 它主要是受此影响的数字文字.