不同类型的重载/多态函数

And*_*dez 2 haskell

我正在学习 Haskell 并遇到一个未解答的问题:

从我的教训来看:

(+) :: Num a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

对于任何数字类型a, (+) 接受 2 个类型的值a并返回一个类型的值a

根据示例:

1 + 1
-- 2 # type a is Int
3.0 + 4.0
-- 7.0 type a is Float
'a' + 'b' 
-- Type Error: Char is not a Numeric type
Run Code Online (Sandbox Code Playgroud)

这是完全有道理的,但我最终不明白后台发生了什么,当:

1 + 3.0
Run Code Online (Sandbox Code Playgroud)

类型推断系统是否会自动将我的 Int 转换为 Float,因为它知道它将返回 Float?

Car*_*arl 7

您应该在 ghci 中调查此类问题。这是非常宝贵的学习资源:

\n
$ ghci\nGHCi, version 9.0.1: https://www.haskell.org/ghc/  :? for help\nghci> :t 1\n1 :: Num p => p\nghci> :t 3.0\n3.0 :: Fractional p => p\nghci> :t 1 + 3.0\n1 + 3.0 :: Fractional a => a\n
Run Code Online (Sandbox Code Playgroud)\n

第一课:数字文字是多态的。1不是 an Int,它是多态的。它可以是Num代码编译所需的任何实例。3.0不是 a Float,它是Fractional代码编译所必需的任何实例。(区别在于文字中的小数 - 它限制了允许的类型。)

\n

第二课:当你将事物组合成一个表达式时,类型就会统一。当你统一NumFractional约束时,你就会得到Fractional约束。这是因为Fractional被定义为要求它的所有实例也是 的实例Num

\n

更多信息,让我们打开警告并查看它们提供了哪些附加信息。

\n
ghci> :set -Wall\nghci> 1\n\n<interactive>:5:1: warning: [-Wtype-defaults]\n    \xe2\x80\xa2 Defaulting the following constraints to type \xe2\x80\x98Integer\xe2\x80\x99\n        (Show a0) arising from a use of \xe2\x80\x98print\xe2\x80\x99 at <interactive>:5:1\n        (Num a0) arising from a use of \xe2\x80\x98it\xe2\x80\x99 at <interactive>:5:1\n    \xe2\x80\xa2 In a stmt of an interactive GHCi command: print it\n1\nghci> 1 + 3.0\n\n<interactive>:6:1: warning: [-Wtype-defaults]\n    \xe2\x80\xa2 Defaulting the following constraints to type \xe2\x80\x98Double\xe2\x80\x99\n        (Show a0) arising from a use of \xe2\x80\x98print\xe2\x80\x99 at <interactive>:6:1-7\n        (Fractional a0) arising from a use of \xe2\x80\x98it\xe2\x80\x99 at <interactive>:6:1-7\n    \xe2\x80\xa2 In a stmt of an interactive GHCi command: print it\n4.0\n
Run Code Online (Sandbox Code Playgroud)\n

打印值时,ghci 要求该类型有一个Show实例。幸运的是,这里的细节并不是太重要,但这就是默认警告引用Show.

\n

这里要观察的教训是,Num如果推理不需要更具体的内容,则具有实例的默认类型是Integer,而不是IntFractional如果推理不需要更具体的内容,则具有实例的默认类型是Double,而不是Float。(Float基本上从未使用过。忘记它的存在。)

\n

因此,当推理运行时,表达式1 + 3.0被推断为具有类型Fractional a => a。如果没有对类型的进一步要求,则默认启动并显示“aDouble”。然后,该信息通过 流回(+)其参数,并要求它们中的每一个也为Double。幸运的是,每个参数都是一个可以采用类型的多态文字Double。类型检查成功,选择实例,进行加法,打印结果。

\n

对于这个过程来说,数字文字是多态的非常重要。Haskell 在任何类型对之间都没有隐式转换。尤其是数字类型。如果您想实际将值从一种类型转换为另一种类型,则必须调用一个函数来执行您想要的转换。(fromIntegralroundfloorceilingrealToFrac是最常见的数值转换函数。)但是当值是多态时,这意味着推理可以选择匹配类型而无需转换。

\n