Haskell 如何为不明确的表达式选择类型

How does Haskell pick a type for an ambiguous expression

如果一个表达式可以用多种方式键入,Haskell 如何选择使用哪一种?

励志例子

举个例子:

$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
Prelude> import Data.Ratio (Ratio)
Prelude Data.Ratio> f z s = show $ truncate $ z + (read s)
Prelude Data.Ratio> :type f
f :: (RealFrac a, Read a) => a -> String -> String
Prelude Data.Ratio> s = take 30 (cycle "12345")
Prelude Data.Ratio> s
"123451234512345123451234512345"
Prelude Data.Ratio> f 0 s
"123451234512345121227855101952"
Prelude Data.Ratio> f (0::Double) s
"123451234512345121227855101952"
Prelude Data.Ratio> f (0::Float) s
"123451235679745417161721511936"
Prelude Data.Ratio> f (0::Ratio Integer) (s ++ "%1")
"123451234512345123451234512345"
Prelude Data.Ratio> show $ truncate $ read s
"123451234512345121227855101952"

当我使用没有任何类型的 0 时,我得到了与 (0::Double) 相同的结果。因此,对我来说 似乎 ,当我调用 f 0 s 时,它使用生成 Doubleread 版本和 Double 的版本 truncateDouble 转换为某种整数类型。我引入了变量 z 这样我就可以在此处轻松控制类型。这样我就可以证明其他解释是可能的,例如使用 Float 或精确比率。那么为什么 Double?最后一行省略了加法,表明该行为与零常数无关。

我猜某些事情告诉 Haskell Double 是比其他类型更规范的类型,无论是在一般情况下还是在用作 RealFrac 时,所以如果它可以解释表达式使用Double 作为中间结果,还有一些其他类型,那么它会更喜欢 Double 解释。

核心问题

自己研究

我读过 https://en.wikibooks.org/wiki/Haskell/Type_basics_II#Polymorphic_guesswork 写道

With no other restrictions, 5.12 will assume the default Fractional type of Double, so (-7) will become a Double as well.

这似乎证实了我的假设,即 Double 在某种程度上被祝福为 RealFrac 的某些父类别的默认类型。它仍然没有为该概念提供名称,也没有提供有关该概念的完整规则列表。

背景

其实我想处理的情况是这样的:

f :: Integer -> String -> Integer
f scale str = truncate $ (fromInteger scale) * (read str)

所以我想要一个接受字符串的函数,将其读取为小数部分,将其与给定数字相乘,然后将结果截断回整数。我很惊讶地发现我没有在任何地方指定中间小数类型就可以编译。

如果存在具有 Num v 约束的模糊类型变量 v,则默认为 IntegerDouble,按该顺序尝试,以满足所有条件者为准v.

的其他限制

这些默认规则在 Haskell 报告中进行了解释:https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-620004

GHC 手册还解释了 GHCi 中的其他默认规则(这意味着在 GHCi 中尝试操作不会让您准确了解编译程序时发生的情况):https://downloads.haskell.org/ghc/latest/docs/html/users_guide/ghci.html#type-defaulting-in-ghci