我有一个关于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
答案 0 :(得分:25)
它是类型defaulting以及ghci的扩展默认规则。
整数文字是多态的,它们的类型为Num a => a
(因为它们代表fromInteger literal
)。但是,当一个表达式被评估时 - 例如打印其结果所必需的 - 表达式必须被赋予单态类型。
本身,
yesno 0
在Num a
上强加了两个约束YesNo a
和0
,整个表达式将具有不明确的类型
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
扩展,否则您的示例在编译模块中没有类型注释时将无法工作。
答案 2 :(得分:1)
在第一种情况下尝试写:
Prelude> yesno (0 :: Int)
False