2

我试图了解类型系统在 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 行的末尾都应该有类型签名。

感谢所有回答的人!

4

3 回答 3

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中有描述

于 2012-08-28T21:50:46.923 回答
4

由于 1 可以具有任何 Num 类型,因此编译器必须使用某种方法来选择某种类型。这是由默认值处理的。但是默认只发生在 Prelude 类而不是你的类。查看 Haskell 报告中有关违约的部分,所有内容都已详细说明。

于 2012-08-28T21:53:45.573 回答
3

有几种数字类型( 的实例Num),当您编写 时,Haskell 不知道您指的是哪一种2。通常你可以摆脱它,因为 ghc/ghci 被编程为选择像 Integer 这样的默认类型来表达2+2. myshow因为 Haskell 正在使用与它自动选择的实例Show相关联的Num实例,而不是在myShow.

您自己的 typeclassMyShow与 没有任何关系Num,因此 Haskell 无法使用默认规则为您选择。[对不起,我以前的版本弄错了。]

这对于像等这样的数字文字来说只是一个奇怪的地方36.7因为它们被重载(可以表示不止一种类型的数据),所以你不会遇到像Charetc这样的其他类型的这个问题。

于 2012-08-28T21:38:59.930 回答