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

时间:2013-05-29 21:22:17

标签: haskell types

我有一个关于GHCi如何假设整数类型的问题。

我正在阅读Yes-No type class of Learn a a Haskell。

如果您想阅读整个内容,请输入以下链接。 http://learnyouahaskell.com/making-our-own-types-and-typeclasses#a-yes-no-typeclass

简单地说,本章说明通过定义我自己的类,我可以创建一个适用于很多类型的函数。

本书定义了带有函数的YesNo类

yesno :: a -> Bool

并将Int作为YesNo类的实例

instance YesNo Int where
    yesno 0 = False
    yesno _ = True

当我在GHCi上加载它并输入

yesno 0

它返回错误。我认为这可能是因为GHCi无法判断0是Int还是Integer还是Double还是Num类中的其他类型。实际上,当我键入yesno(0 :: Int)时,它可以工作。

为了好玩,我将Integer作为YesNo类的一个实例并写了

instance YesNo Integer where
    yesno 0 = True
    yesno _ = False

(注意我翻转了True和False) 再次,我输入了

yesno 0

(没有任何类型声明)然后GHCi显示True

此外,当我输入

yesno $ fromIntegral 0

它返回True,这意味着GHCi认为fromIntegral 0的类型为Integer

那么,这是否意味着当我在GHCi上输入一个整数时,它通常假定其值为Integer而不是?我感到困惑,因为:t 0会返回Num a => a

3 个答案:

答案 0 :(得分:25)

它是类型defaulting以及ghci的扩展默认规则。

整数文字是多态的,它们的类型为Num a => a(因为它们代表fromInteger literal)。但是,当一个表达式被评估时 - 例如打印其结果所必需的 - 表达式必须被赋予单态类型。

本身,

yesno 0

Num a上强加了两个约束YesNo a0,整个表达式将具有不明确的类型

yesno 0 :: (Num a, YesNo a) => Bool

(这是不明确的,因为约束中的类型变量无法从=>右侧的类型到达。

通常,模糊类型是类型错误,但是,在某些情况下,通过使用默认类型实例化约束类型变量来解决模糊性。语言规范中的规则是,如果

,则可以默认类型变量
  

在发现模糊类型的情况下,如果出现以下情况,则模糊类型变量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.)

约束(Num a, YesNo a)符合前两个要求,但不符合第三个要求。因此,根据语言标准,它不是默认的,应该是类型错误。

但是,ghci使用扩展的默认规则,并且默认类型变量受Prelude或标准库中未定义的类约束。

然后在此处选择Num约束的默认值,除非显式默认声明在范围内,即Integer,或者,如果Integer不满足约束,Double已经过尝试。

因此,当您拥有instance YesNo Integer时,ghci可以成功将类型变量a默认为Integer。但是没有这样的实例,默认失败是因为没有一个默认候选者有实例。

答案 1 :(得分:8)

  

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

是。基本上,GHCi将首先尝试Integer,然后如果失败,Double然后最后()来解决模糊类型约束。你可以read the details about how this works in the GHC User's Guide

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

将提供与GHCi相同的行为。

答案 2 :(得分:1)

在第一种情况下尝试写:

Prelude> yesno (0 :: Int)
False