在 `Num` 实例上除法 Haskell

Division in Haskell on `Num` instances

考虑 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.

中的数字转换必须明确

谢谢!

I thought that numeric conversions had to be explicit in Haskell.

这是正确的,但这里我们有 数字文字。如果你写 2,那就是 而不是 本身是一个 Int,或者一个 Integer。我们当时还不知道。

如果我们再比如写2 / 3,那么Haskell会得出我们使用的函数(/) :: Fractional a => a -> a -> a,所以得出23 应该是 Fractional,所以在这种情况下它将使用浮点解析器来解析 2 文字。

如果您明确声明 2 是一个 Int,那么它将出错:

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,Haskell 无法将其解析为支持 (/) 函数的类型。

现在,如果我们分析 sum [1,2,3],请更具体地针对您的问题。 sum 具有类型 sum :: Num a => [a] -> a,因此如果列表的元素是 Fractional,则 sum ... 也具有 Fractional 类型。

对于分母,您实际上进行了 显式 转换。确实,你写fromIntegral (length [1,2,3])。现在 length :: [a] -> Int returns 一个 IntfromIntegral 会将任何 Integral 类型转换为通用 Num 类型。所以它可以将 Int 转换为 Float.