Haskell:YesNo类型.为什么整数?

Ten*_*ngu 22 haskell types

我有一个关于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是否意味着是IntIntegerDouble或其他类型的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 0Integer.

那么,这是否意味着当我在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 aYesNo a0,并且整个表达将具有不明确的类型

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可以成功地将类型变量默认aInteger.但是没有这样的实例,默认失败是因为没有一个默认候选者有实例.


ham*_*mar 8

那么,这是否意味着当我在GHCi上输入一个整数时,通常假设它的值是整数?

是.基本上,GHCi将首先尝试Integer,然后如果失败,Double然后最终()解决模糊类型约束.您可以在GHC用户指南中阅读有关其工作原理的详细信息.

但请注意,在已编译的模块中,规则更严格一些.特别是,默认仅适用于标准类,因此除非您启用与ExtendedDefaultRulesGHCi具有相同行为的扩展,否则您的示例在编译模块中没有类型注释时将无法工作.