Haskell:通过`fromIntegral`

时间:2019-04-04 21:47:36

标签: haskell types

了解fromIntegral的类型转换

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

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

请注意,我必须如何使用fromIntegral来确保x的类型适合(/)运算符。如果x是整数类型,那将行不通。对GHCI中的函数进行类型检查会得到以下信息:

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

Prelude> :t (/)
(/) :: Fractional a => a -> a -> a

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

NumFractional上方,这意味着并非每个Num-Type都是Fractional。那么,为什么(/)接受通用的Num类型作为参数呢?

我认为是因为fromIntegral并没有真正转换为Num(那些甚至不能实例化,它们吗?只能由具体类型继承),而是直接转换为DoubleFloat

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

1 个答案:

答案 0 :(得分:5)

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

fromIntegral :: Int -> Integer
fromIntegral :: Int -> Word
fromIntegral :: Integer -> Double

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

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

因为(/)要求使用Fractional类型。

然后使用默认机制来修复n

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

相反,您可能希望得到结果

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

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