Haskell在`Num`实例上划分

abl*_*din 1 haskell type-conversion division

请考虑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
Run Code Online (Sandbox Code Playgroud)

据我所知,这两个sum [1,2,3]fromIntegral (length [1,2,3])的实例Num.令我困惑的是,为什么编译器将操作数转换为Fractional?我认为数字转换必须在Haskell中显式化.

谢谢!

Wil*_*sem 6

我认为数字转换必须在Haskell中显式化.

这是正确的,但在这里我们有数字文字.如果你写2,那本身就不是Int,或者是Integer.那时我们不知道.

如果我们然后编写2 / 3,那么Haskell将派生我们使用一个函数(/) :: Fractional a => a -> a -> a,因此它得出结论2并且3应该是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
Run Code Online (Sandbox Code Playgroud)

因此,通过强制Haskell使用Int,Haskell认为无法将其解析为支持该(/)函数的类型.

如果我们分析,现在让它更具体地针对您的问题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成a Float.