为什么我能这样做:
1 + 2.0
Run Code Online (Sandbox Code Playgroud)
但是当我尝试:
let a = 1
let b = 2.0
a + b
<interactive>:1:5:
Couldn't match expected type `Integer' with actual type `Double'
In the second argument of `(+)', namely `b'
In the expression: a + b
In an equation for `it': it = a + b
Run Code Online (Sandbox Code Playgroud)
这看起来很奇怪!它会绊倒你吗?
PS:我知道"1"和"2.0"是多态常数.这不是让我担心的问题.我担心的是,为什么不哈斯克尔一个在第一种情况下的事情,但另一个在第二!
Jef*_*rka 20
类型签名(+)定义为Num a => a -> a -> a,这意味着它适用于Num类型类的任何成员,但两个参数必须属于同一类型.
这里的问题是GHCI和它建立类型的顺序,而不是Haskell本身.如果你要将你的任何一个例子放在一个文件中(do用于let表达式),它将编译并运行正常,因为GHC将使用整个函数作为上下文来确定文字的类型1和2.0.
在第一种情况下发生的所有事情都是GHCI猜测你输入的数字的类型.最精确的是a Double,所以它只是假设另一个应该是a Double并执行计算.但是,当你使用let表达式时,它只有一个数字可以解决,所以它决定1是一个Integer并且2.0是一个Double.
编辑:GHCI并不是真正"猜测",它使用的是Haskell报告中定义的非常具体的类型默认规则.你可以在这里阅读更多相关内容.
Dan*_*her 11
第一个是有效的,因为数字文字是多态的(它们被解释为fromInteger literalresp.fromRational literal),所以在没有其他约束的情况下1 + 2.0,你确实有fromInteger 1 + fromRational 2结果类型默认为Double.
第二次却不会因为单态限制的工作.如果绑定没有类型签名和简单模式绑定(name = expresion)的东西,则该实体被赋予一个单形类型.对于文字1,我们有一个Num约束,因此,根据默认规则,其类型默认为Integer绑定let a = 1.同样,小数文字的类型默认为Double.
顺便说一下,如果你:set -XNoMonomorphismRestriction在ghci ,它会起作用.
单态限制的原因是为了防止共享丢失,如果你看到一个看起来像常量的值,你不希望它被计算多次,但是如果它有多态类型,它会在每次重新计算时重新计算它被使用了.
您可以使用GHCI进一步了解这一点.使用该命令:t获取表达式的类型.
Prelude> :t 1
1 :: Num a => a
Run Code Online (Sandbox Code Playgroud)
所以1是一个常数,其可以是任何数值类型(Double,Integer等)
Prelude> let a = 1
Prelude> :t a
a :: Integer
Run Code Online (Sandbox Code Playgroud)
所以在这种情况下,Haskell推断出具体类型为ais Integer.同样,如果你写,let b = 2.0那么Haskell推断出类型Double.使用let制作的Haskell推断出比(或许)更具体的类型是必要的,这会导致您的问题.(比我有更多经验的人也许可以评论为什么会这样.)既然(+)有了类型Num a => a -> a -> a,那么这两个参数需要具有相同的类型.
您可以使用以下fromIntegral功能解决此问题:
Prelude> :t fromIntegral
fromIntegral :: (Num b, Integral a) => a -> b
Run Code Online (Sandbox Code Playgroud)
此函数将整数类型转换为其他数字类型.例如:
Prelude> let a = 1
Prelude> let b = 2.0
Prelude> (fromIntegral a) + b
3.0
Run Code Online (Sandbox Code Playgroud)