为什么不工作: -
(length [1,2,3,4]) + 3.2
虽然有效: -
2+3.3
据我所知,在第一种情况下,结果是Int + Float,但在第二种情况下也不一样,或者Haskell自动推断出第二种情况下的类型: - Num + Num,而它确实在第一种情况下不这样做?
答案 0 :(得分:12)
Haskell 从不为您进行隐式类型转换。 +
只能处理两个相同类型的数字,并且也会将该类型作为结果。正如您在+
示例中所看到的那样,(length [1,2,3,4]) + 3.2
的任何其他用法都是错误的。
但是,Haskell中的数字文字会被重载。 2
可以是任何数字类型,3.3
可以是任何小数类型。因此,当Haskell看到表达式2 + 3.3
时,它可以尝试查找既是“数字”又是“小数”的类型,并将这两个数字视为该类型,以便添加将起作用。
更准确地说,+
的类型为Num a => a -> a -> a
。 2
本身的类型为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
,而不是文字,因此您需要明确转换其值。