为什么不能在haskell中添加Int和浮点数

时间:2013-08-08 07:56:42

标签: haskell

为什么不工作: -

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

虽然有效: -

2+3.3

据我所知,在第一种情况下,结果是Int + Float,但在第二种情况下也不一样,或者Haskell自动推断出第二种情况下的类型: - Num + Num,而它确实在第一种情况下不这样做?

3 个答案:

答案 0 :(得分:12)

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

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

更准确地说,+的类型为Num a => a -> a -> a2本身的类型为Num a => a,而3.3本身的类型为Fractional a => a。将这3种类型放在一起,表达式2 + 3.3中的两个数字都可以被赋予Fractional a => a类型,因为所有Fractional类型也是Num类型,这也满足+的类型。 (如果您将此表达式键入GHCi,a将填入Double,因为GHC必须将类型默认为某些内容才能对其进行评估)

在表达式(length [1,2,3,4]) + 3.2中,3.2仍然过载(并且单独存在类型Fractional a => a)。但length [1,2,3,4]的类型为Int。由于一边是固定的具体类型,因此满足+类型的唯一方法是使用a填充另一种类型的Int,但这会违反Fractional 1}}约束; 3.2无法成为Int。所以这个表达式不是很好。

但是,任何Integral类型(其中Int为1)都可以通过应用Num转换为任何 fromIntegral类型(此实际上,如2这样的整数文字可以被视为任何数字类型)。所以(fromIntegral $ length [1,2,3,4]) + 3.2会有用。

答案 1 :(得分:10)

在第一种情况下,正如您所提到的,length [1,2,3,4]明确是Int,无法隐式转换为Float或任何Fractional实例。在第二种情况下,没有明确的输入,因此Haskell可以推断出良好的类型是Fractional的实例。您可以在the corresponding section (§6.4.1) of the Haskell 2010 report中看到编译器如何处理数字文字。

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

答案 2 :(得分:7)

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