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
时,它使用生成 Double
的 read
版本和 Double
的版本 truncate
将 Double
转换为某种整数类型。我引入了变量 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
,则默认为 Integer
或 Double
,按该顺序尝试,以满足所有条件者为准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
如果一个表达式可以用多种方式键入,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
时,它使用生成 Double
的 read
版本和 Double
的版本 truncate
将 Double
转换为某种整数类型。我引入了变量 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
,则默认为 Integer
或 Double
,按该顺序尝试,以满足所有条件者为准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