ghci - 在交互模式下急切的编译?

时间:2012-02-28 22:24:38

标签: haskell ghci

以下程序类型检查我是否在命令行上指定它(例如ghci file.hs):

import Data.Ratio
foo = let x = [1..]
          y = (1%2) + (head x)
       in y

但是,如果我以交互方式输入它,我将收到类型错误:

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'

似乎x被急切地输入为[Integer],而不是更为笼统的(Num t, Enum t) => [t]

我能做些什么吗?是否存在交互模式与批处理模式不同的其他情况?

2 个答案:

答案 0 :(得分:10)

没有参数的绑定,即x = ...形式的绑定受monomorphism restriction的约束,这意味着GHC将尝试使用任何可用的类型信息使其成为非多态的,并且重新开始type defaulting解决任何含糊之处。 (实际上,GHCi使用a slightly more permissive set of defaulting rules,但这对这个问题并不重要。)

由于在编写let x = [1..]时没有其他类型信息可用,因此键入默认会导致类型被推断为[Integer],因为Integer是默认的数字类型。

有几种方法可以解决这个问题:

  1. 使用类型签名。这总是有效,但在处理复杂类型时有时会很乏味。

    > let x = [1..] :: [Rational]
    
  2. 使用参数编写绑定。这不适用于您的情况,但在编写无点函数定义时有时会看到此问题。

    > let f = (+)
    > :t f
    f :: Integer -> Integer -> Integer
    > let f x y = x + y
    > :t f
    f :: Num a => a -> a -> a
    
  3. 为类型检查器提供更多信息。在您的情况下,我们可以通过在一个let语句中编写两个绑定来避免此问题。然后,GHC可以使用第二个绑定中的类型信息来正确推断x应该具有类型[Rational]

    > let x = [1..]; y = 1%2 + head x
    > :t x
    x :: [Ratio Integer]
    
  4. 禁用单态限制。如果您期望某些内容的类型,则可能会产生严重的性能影响。一个Integer,虽然它实际上是Num a => a,因为后者必须每次重新计算,而前者可以共享。这是限制存在的主要原因。

    然而,在翻译中,这通常不是一个问题,所以方便通常是值得的。

    > :set -XNoMonomorphismRestriction
    > let x = [1..]
    > :t x
    x :: (Num t, Enum t) => [t]
    

    如果您希望在默认情况下启用此功能,则可以将其添加到.ghci file

答案 1 :(得分:4)

可以通过将x定义为以下内容来做一些事情:

let x = [1..] :: [Ratio Int]

如:

Data.Ratio Prelude> let x = [1..] :: [Ratio Int]
Data.Ratio Prelude> let y = (1%2) + (head x)
Data.Ratio Prelude> y
3 % 2
Data.Ratio Prelude>