我试图了解类型系统在 Haskell 中是如何工作的。
class (Show a) => MyShow a where
myShow :: a -> String
instance MyShow Integer where
myShow = show
myshow :: (Show a) => a -> String
myshow = show
main = do
putStrLn $ myshow 1
putStrLn $ myShow (2 :: Integer) -- why do I need '::Integer' here?
为什么“myshow 1”在没有类型的情况下工作,而“myshow 2”在没有明确类型的情况下会导致错误:
Ambiguous type variable `a0' in the constraints:
(MyShow a0) arising from a use of `myShow'
at nooverinst.hs:12:16-21
(Num a0) arising from the literal `2' at nooverinst.hs:12:23
Probable fix: add a type signature that fixes these type variable(s)
In the second argument of `($)', namely `myShow 2'
In the expression: putStrLn $ myShow 2
In the expression:
do { putStrLn $ myshow 1;
putStrLn $ myShow 2 }
同样奇怪的是,使用GHCI的时候没有报错:
*Main> myShow 2
"2"
那么,在这种情况下,“myshow”和“myShow”有什么区别?它们都被定义为与“show”相同。我错过了什么?
更新:
答案摘要:此行为与违约有关。'show 1' 和 'myshow 1' 工作的事实是一个特例(参见Haskell 报告中关于 defaulting的部分)。在源代码之上添加“default ()”会关闭默认设置并导致“myshow 1”处的代码中断,因为不再通过默认设置来解决类型歧义。所以,事实上,两个 putStrLn 行的末尾都应该有类型签名。
感谢所有回答的人!