以下程序类型检查我是否在命令行上指定它(例如ghci file.hs
):
import Data.Ratio
foo = let x = [1..]
y = (1%2) + (head x)
in y
Run Code Online (Sandbox Code Playgroud)
但是,如果我以交互方式输入它,我将收到类型错误:
Prelude> import Data.Ratio
Prelude Data.Ratio> let x = [1..]
Prelude Data.Ratio> let y = (1%2) + (head x)
<interactive>:1:23:
Couldn't match expected type `Ratio a0' with actual type `Integer'
Run Code Online (Sandbox Code Playgroud)
它似乎x
正在急切地打字,[Integer]
而不是更普遍的(Num t, Enum t) => [t]
.
我能做些什么吗?是否存在交互模式与批处理模式不同的其他情况?
ham*_*mar 10
没有参数的绑定,即形式的绑定x = ...
受单形态限制的约束,这意味着GHC将尝试使用可用的任何类型信息使其成为非多态的,并且返回类型默认以解决任何歧义.(实际上,GHCi使用了一组稍微宽松的默认规则,但这对于这个问题并不重要).
由于在编写时没有其他类型信息可用let x = [1..]
,因此键入默认会导致类型被推断为[Integer]
,因为Integer
它是默认的数字类型.
有几种方法可以解决这个问题:
使用类型签名.这总是有效,但在处理复杂类型时有时会很乏味.
> let x = [1..] :: [Rational]
Run Code Online (Sandbox Code Playgroud)用参数写出绑定.这不适用于您的情况,但您在编写无点函数定义时有时会看到此问题.
> let f = (+)
> :t f
f :: Integer -> Integer -> Integer
> let f x y = x + y
> :t f
f :: Num a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)为类型检查器提供更多信息.在您的情况下,我们可以通过在一个let
语句中编写两个绑定来避免此问题.然后GHC可以使用来自第二个绑定的类型信息来正确地推断x
应该具有该类型[Rational]
.
> let x = [1..]; y = 1%2 + head x
> :t x
x :: [Ratio Integer]
Run Code Online (Sandbox Code Playgroud)禁用单态限制.如果您期望某种类型的东西是例如a Integer
,而实际上是a Num a => a
,则可能会产生严重的性能影响,因为后者必须在每次共享时重新计算.这是限制存在的主要原因.
但是,在解释器中,这通常不是问题,因此便利性通常是值得的.
> :set -XNoMonomorphismRestriction
> let x = [1..]
> :t x
x :: (Num t, Enum t) => [t]
Run Code Online (Sandbox Code Playgroud)
如果您希望在默认情况下启用此功能,则可以将其添加到.ghci
文件中.