为什么这不起作用:-
(length [1,2,3,4]) + 3.2
虽然这有效: -
2+3.3
我知道在第一种情况下结果是 Int+Float 但在第二种情况下也不相同,或者 Haskell 会自动推断第二种情况下的类型为:- Num+Num 而它不这样做在第一种情况下?
为什么这不起作用:-
(length [1,2,3,4]) + 3.2
虽然这有效: -
2+3.3
我知道在第一种情况下结果是 Int+Float 但在第二种情况下也不相同,或者 Haskell 会自动推断第二种情况下的类型为:- Num+Num 而它不这样做在第一种情况下?
Haskell从不为您进行隐式类型转换。+
仅适用于相同类型的两个数字,并为您提供该类型作为结果。+
正如您在(length [1,2,3,4]) + 3.2
示例中看到的那样,任何其他用法都是错误的。
但是,数字文字在 Haskell 中是重载的。2
可以是任何数字类型,也3.3
可以是任何小数类型。因此,当 Haskell 看到表达式时2 + 3.3
,它可以尝试找到一个既是“数字”又是“分数”的类型,并将这两个数字都视为该类型,这样加法就会起作用。
更准确地说,+
有类型Num a => a -> a -> a
。2
on its own 是 type Num a => a
,3.3
on its own is of type Fractional a => a
。将这 3 种类型放在一起,表达式中的2 + 3.3
两个数字都可以被赋予 type Fractional a => a
,因为所有Fractional
类型也是Num
类型,这也满足 的类型+
。(如果您在 GHCi 中键入此表达式,则会a
填写为Double
,因为 GHC 必须将类型默认为某个值才能对其进行评估)
在表达式(length [1,2,3,4]) + 3.2
中, the3.2
仍然是重载的(并且孤立地会有 type Fractional a => a
)。但length [1,2,3,4]
有类型Int
。由于一侧是固定的具体类型,满足 for 类型的唯一方法+
是用 填充a
另一类型的Int
,但这违反了Fractional
约束;没有办法3.2
成为一个Int
。所以这个表达式不是很好的类型。
但是,任何Integral
类型(其中Int
之一)都可以通过应用转换为任何 Num
类型fromIntegral
(这实际上是整数文字2
可以被视为任何数字类型的方式)。所以(fromIntegral $ length [1,2,3,4]) + 3.2
会起作用。
正如您所提到的,在第一种情况下,它length [1,2,3,4]
是显式的Int
,并且不能隐式转换为 aFloat
或任何Fractional
实例。而在第二种情况下,没有显式类型,因此 Haskell 可以推断出好的类型是Fractional
. 您可以在 Haskell 2010 报告的相应部分(第 6.4.1 节)中查看编译器如何处理数字文字。
一种解决方法:(fromIntegral $ length [1,2,3,4]) + 3.2
整数文字,例如在您的第二个示例中,被编译器2
隐式处理。fromInteger 2
这意味着它们被转换为任何需要的数字类型,因为fromInteger
它的返回类型是多态的;在这种情况下,Float
使用。但是,length [1,2,3,4]
是 type Int
,而不是文字,因此您需要显式转换其值。