4

为什么这不起作用:-

(length [1,2,3,4]) + 3.2

虽然这有效: -

2+3.3

我知道在第一种情况下结果是 Int+Float 但在第二种情况下也不相同,或者 Haskell 会自动推断第二种情况下的类型为:- Num+Num 而它不这样做在第一种情况下?

4

3 回答 3

13

Haskell从不为您进行隐式类型转换。+仅适用于相同类型的两个数字,并为您提供该类型作为结果。+正如您在(length [1,2,3,4]) + 3.2示例中看到的那样,任何其他用法都是错误的。

但是,数字文字在 Haskell 中是重载的。2可以是任何数字类型,也3.3可以是任何小数类型。因此,当 Haskell 看到表达式时2 + 3.3,它可以尝试找到一个既是“数字”又是“分数”的类型,并将这两个数字都视为该类型,这样加法就会起作用。

更准确地说,+有类型Num a => a -> a -> a2on its own 是 type Num a => a3.3on 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会起作用。

于 2013-08-08T08:32:35.513 回答
10

正如您所提到的,在第一种情况下,它length [1,2,3,4]是显式的Int,并且不能隐式转换为 aFloat或任何Fractional实例。而在第二种情况下,没有显式类型,因此 Haskell 可以推断出好的类型是Fractional. 您可以在 Haskell 2010 报告的相应部分(第 6.4.1 节)中查看编译器如何处理数字文字。

一种解决方法:(fromIntegral $ length [1,2,3,4]) + 3.2

于 2013-08-08T08:02:41.477 回答
8

整数文字,例如在您的第二个示例中,被编译器2隐式处理。fromInteger 2这意味着它们被转换为任何需要的数字类型,因为fromInteger它的返回类型是多态的;在这种情况下,Float使用。但是,length [1,2,3,4]是 type Int,而不是文字,因此您需要显式转换其值。

于 2013-08-08T08:09:03.193 回答