我试图理解类型系统在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 report section on defaulting)。在源代码之上添加'default()'会关闭默认值并导致代码在'myshow 1'处中断,因为类型歧义不再通过默认来解决。所以,实际上,两个putStrLn行最后都应该有类型签名。
感谢所有回答的人!
答案 0 :(得分:9)
这与默认(Haskell标准的一个较暗角落)有关,如http://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-790004.3.4所述
简而言之,Haskell以一种特殊的方式处理数值类,并默认自动产生数值类的歧义,但如果涉及的其他约束是基类,则仅。从这个意义上讲,Show
也很特殊,您自己定义的MyShow
将以不同的方式处理。
在GHCi中,扩展的默认规则启动,这略微放宽了限制。这些在http://www.haskell.org/ghc/docs/latest/html/users_guide/interactive-evaluation.html#extended-default-rules
中描述答案 1 :(得分:4)
由于1可以具有任何Num类型,因此编译器必须使用某种方法来选择某种类型。这是由违约处理的。但默认只发生在Prelude课程而不是你的课程。查看有关Haskell报告中的默认值的部分,并将其全部拼写出来。
答案 2 :(得分:3)
有几种数字类型(Num
的实例),而Haskell在您编写2
时并不知道您的意思。
通常你可以逃脱它,因为ghc / ghci被编程为像2+2
这样的表达式选择像Integer这样的默认类型。
您正在myshow
中使用它,因为Haskell使用的Show
实例与自动选择的Num
实例相关联,但不在myShow
中。
您自己的类型类MyShow
与Num
没有任何关系,因此Haskell无法使用默认规则为您选择。
[抱歉,我的上一版本错误地解决了这个问题。]
这只是3
,6.7
等数字文字的一种奇怪现象,因为它们已经过载(可以代表多种类型的数据),所以你不会遇到这个问题其他类型,如Char
等。