我有一个关于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用户指南中阅读有关其工作原理的详细信息.
但请注意,在已编译的模块中,规则更严格一些.特别是,默认仅适用于标准类,因此除非您启用与ExtendedDefaultRulesGHCi具有相同行为的扩展,否则您的示例在编译模块中没有类型注释时将无法工作.