【发布时间】:2019-04-04 21:47:35
【问题描述】:
通过fromIntegral理解类型转换
所以,我最近遇到了很多类型转换错误。这让我开始使用fromIntegral,尽管我对它的工作方式感到很困惑。
minimalExample :: Integer -> Integer
minimalExample a = truncate y
where
x = fromIntegral (a + 10)
y = x - 12 * (x / 13)
注意我必须如何使用fromIntegral 来确保x 是(/) 运算符的正确类型。如果 x 是 Integral 类型,它就不会起作用。对 GHCI 中的函数的类型检查给了我这个信息:
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
Prelude> :t (/)
(/) :: Fractional a => a -> a -> a
显然fromIntegral 将Int/Integer 转换为一些Num 类类型(哪个?我不知道)。除法中缀运算符需要两个分数作为输入。现在看看this graphic,它总结了 Haskell 中的标准类型-类-关系。
Num 高于Fractional,这意味着不是每个Num-Type 都是Fractional。那么为什么(/) 接受一个通用的Num-type 作为参数呢?
我认为这是因为fromIntegral 并没有真正转换为Num(它们甚至都不能实例化,是吗?只能由具体类型继承),而是直接转换为Double 或Float。
如果是这样,它实际上转换为哪一个?为什么它实际上不在其定义中列出具体类型,而不是模糊和通用的Num 类类型?
【问题讨论】:
-
“那么为什么 (/) 接受一个通用的 Num 类型作为参数呢?”它没有。它只接受
Fractional的实例。但是由于Fractional是Num的子类,并且fromIntegral可以生成任何Num,fromIntegral也可以生成Fractional- 因为它必须与(/)一起使用。至于为什么这些函数没有在其定义中列出具体类型,那是因为这会不必要地限制它们的使用——但由于是多态的,它们可以在更多情况下使用。 -
PS 最近在this question 有很多类似的问题讨论
-
“显然 fromIntegral 将 Int/Integer 转换为某种 Num 类类型(哪个?我不知道)。”我喜欢将其视为一个非确定性函数,它将其参数转换为具有
Num实例的 all 类型的值。这些值以叠加的形式存在,直到您“观察”到所请求类型的值。