请考虑以下GHCI的摘录:
Prelude> :t sum [1,2,3]
sum [1,2,3] :: Num a => a
Prelude> :t fromIntegral (length [1,2,3])
fromIntegral (length [1,2,3]) :: Num b => b
Prelude> :t sum [1,2,3] / fromIntegral (length [1,2,3])
sum [1,2,3] / fromIntegral (length [1,2,3]) :: Fractional a => a
我了解sum [1,2,3]
和fromIntegral (length [1,2,3])
都是Num
的实例。令我困惑的是,为什么编译器将操作数转换为Fractional
?我认为数字转换必须在Haskell中明确。
谢谢!
答案 0 :(得分:6)
我认为数字转换必须在Haskell中明确。
这是正确的,但这里我们有数字文字。如果你写2
,不本身就是Int
或Integer
。那时我们不知道。
如果我们然后编写2 / 3
,那么Haskell将推导出我们使用函数(/) :: Fractional a => a -> a -> a
,因此得出结论:2
和3
应该是{{1在这种情况下,它将使用浮点解析器来解析Fractional
文字。
如果您明确声明2
是2
,那么它就会出错:
Int
因此,通过强制Haskell使用Prelude> (2 :: Int) / 3
<interactive>:4:1: error:
• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: (2 :: Int) / 3
In an equation for ‘it’: it = (2 :: Int) / 3
,Haskell认为无法将其解析为支持Int
函数的类型。
现在,如果我们分析(/)
,请更具体地说明您的问题。 sum [1,2,3]
的类型为sum
,因此如果列表中的元素为sum :: Num a => [a] -> a
,则Fractional
也会有sum ...
类型。
对于分母,您实际进行显式转换。的确,你写Fractional
。现在fromIntegral (length [1,2,3])
会返回length :: [a] -> Int
。 Int
会将任何fromIntegral
类型转换为通用Integral
类型。因此,它可以将Num
转换为Int
。