我有一个关于GHCi如何假设整数的类型的问题.
我正在阅读是 - 没有类型的类学习你哈斯克尔.
如果你想阅读整个内容,这里有一个链接. http://learnyouahaskell.com/making-our-own-types-and-typeclasses#a-yes-no-typeclass
简而言之,本章说明通过定义我自己的类,我可以创建一个适用于很多类型的函数.
本书定义了具有函数的YesNo类
yesno :: a -> Bool
Run Code Online (Sandbox Code Playgroud)
并Int
作为YesNo类的实例
instance YesNo Int where
yesno 0 = False
yesno _ = True
Run Code Online (Sandbox Code Playgroud)
当我把它加载到我的GHCi上并输入时
yesno 0
Run Code Online (Sandbox Code Playgroud)
它返回错误.我认为这可能是因为GHCI不能告诉0是否意味着是Int
或Integer
或Double
或其他类型的Num
类.实际上,当我键入yesno(0 :: Int)时,它起作用了.
所以只是为了我Integer
作为YesNo
课堂实例而写的乐趣
instance YesNo Integer where
yesno 0 = True
yesno _ = False
Run Code Online (Sandbox Code Playgroud)
(注意我翻转了True和False)并再次输入
yesno 0
Run Code Online (Sandbox Code Playgroud)
(没有任何类型声明)然后GHCi显示True
.
而且,当我输入
yesno $ fromIntegral 0
Run Code Online (Sandbox Code Playgroud)
它返回了True
,这意味着GHCi认为的类型fromIntegral 0
是Integer
.
那么,这是否意味着当我在GHCi上输入一个整数时,它通常假定它的值Integer
代替?我很困惑因为:t 0
回归Num a => a
Dan*_*her 26
它的类型默认与ghci的扩展默认规则一起.
整数文字是多态的,它们具有类型Num a => a
(因为它们代表fromInteger literal
).但是,当一个表达式被评估时 - 例如打印其结果所必需的 - 表达式必须被赋予单态类型.
通过它自己,
yesno 0
Run Code Online (Sandbox Code Playgroud)
强加两个约束Num a
和YesNo a
上0
,并且整个表达将具有不明确的类型
yesno 0 :: (Num a, YesNo a) => Bool
Run Code Online (Sandbox Code Playgroud)
(它是不明确的,因为约束中的类型变量不能从右边的类型到达=>
).
通常,模糊类型是类型错误,但是,在某些情况下,通过使用默认类型实例化约束类型变量来解决模糊性.语言规范中的规则是如果类型变量可以默认
在发现模糊类型的情况下,如果出现以下情况,则模糊类型变量
v
是可以违约的:
- `v` appears only in constraints of the form `C v`, where `C` is a class, and
- at least one of these classes is a numeric class, (that is, `Num` or a subclass of `Num`), and
- all of these classes are defined in the Prelude or a standard library (Figures 6.2–6.3 show the numeric classes, and Figure 6.1 shows the classes defined in the Prelude.)
Run Code Online (Sandbox Code Playgroud)
约束(Num a, YesNo a)
符合前两个要求,但不符合第三个要求.因此,根据语言标准,它不是默认的,应该是类型错误.
但是,ghci使用扩展的默认规则,并且默认类型变量受Prelude或标准库中未定义的类约束.
然后,它将Num
在此处选择约束的默认值,除非显式默认声明在范围内,否则Integer
,或者,如果Integer
不满足约束,Double
则尝试.
所以当你有一个时instance YesNo Integer
,ghci可以成功地将类型变量默认a
为Integer
.但是没有这样的实例,默认失败是因为没有一个默认候选者有实例.
那么,这是否意味着当我在GHCi上输入一个整数时,通常假设它的值是整数?
是.基本上,GHCi将首先尝试Integer
,然后如果失败,Double
然后最终()
解决模糊类型约束.您可以在GHC用户指南中阅读有关其工作原理的详细信息.
但请注意,在已编译的模块中,规则更严格一些.特别是,默认仅适用于标准类,因此除非您启用与ExtendedDefaultRules
GHCi具有相同行为的扩展,否则您的示例在编译模块中没有类型注释时将无法工作.