Haskell:通过`fromIntegral`了解类型转换机制

Stc*_*b12 2 haskell types

通过了解类型转换 fromIntegral

因此,最近我遇到了很多类型转换错误。这使我开始使用fromIntegral,尽管我对它的工作方式感到困惑。

minimalExample :: Integer -> Integer
minimalExample a = truncate y
    where
        x = fromIntegral (a + 10)
        y = x - 12 * (x / 13)
Run Code Online (Sandbox Code Playgroud)

请注意,我必须使用fromIntegral哪种方式确保操作员的x类型正确(/)。如果x是Integral类型,那将行不通。对GHCI中的函数进行类型检查会得到以下信息:

Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b

Prelude> :t (/)
(/) :: Fractional a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

显然fromIntegralInt/ Integer转换为某些Num类类型(哪个?我不知道)。除法中缀运算符期望两个小数作为输入。现在看一下该图,该图总结了Haskell中的标准type-class-relations。

Num在上面Fractional,这意味着不是每个Num-Type都是一个Fractional。那么为什么要(/)接受泛型Num-type作为参数呢?

我认为这是因为fromIntegral并没有真正转换为a Num(那些甚至都不可实例化,对吗?只能由具体类型继承),而是直接转换为a Double或a Float

如果是这样,它将实际转换为哪一个?而且为什么它实际上没有在定义中列出该具体类型,而不是模糊和通用Num类类型?

dfe*_*uer 5

fromIntegral不会转换为一些模糊的未知Num类型。它将转换为所需的内容。也就是说,fromIntegral不要选择自己的结果类型。呼叫者可以。所以

fromIntegral :: Int -> Integer
fromIntegral :: Int -> Word
fromIntegral :: Integer -> Double
Run Code Online (Sandbox Code Playgroud)

等等,在这种情况下,类型检查器会推断出

minimalExample :: Integer -> Integer
minimalExample a = truncate y
  where
    x, y :: Fractional n => n
    x = fromIntegral (a + 10)
    y = x - 12 * (x / 13)
Run Code Online (Sandbox Code Playgroud)

因为(/)需要一种Fractional类型。

然后默认机制开始修复n

minimalExample :: Integer -> Integer
minimalExample a = truncate y
  where
    x, y :: Double
    x = fromIntegral (a + 10)
    y = x - 12 * (x / 13)
Run Code Online (Sandbox Code Playgroud)

您可能希望这会变成事实

minimalExample :: Integer -> Integer
minimalExample a = truncate (y :: Double)
  where
    x, y :: Fractional n => n
    x = fromIntegral (a + 10)
    y = x - 12 * (x / 13)
Run Code Online (Sandbox Code Playgroud)

我当然做到了!但事实并非如此。可怕的单态性约束开始起作用,x并且y在约束类型中成为单态性n,因为它们不是(从语法上)函数。是的,单态性限制很奇怪。