理解为什么a / b不起作用,但是来自整数a / fromInteger b

时间:2013-04-26 20:21:35

标签: haskell

在Haskell中,这有效:

ghci>5/2
2.5

大。但是,如果我将5和2分配给变量..

Main> let a = 5
Main> let b = 2
Main> a/b
<interactive>:68:2:
    No instance for (Fractional Integer)
      arising from a use of `/'
    Possible fix: add an instance declaration for (Fractional Integer)
    In the expression: a / b
    In an equation for `it': it = a / b
Main>

我在wazoo上犯了错误。我能绕过它的唯一方法是说:

*Main> fromInteger a / fromInteger b
2.5
*Main>

fromInteger发生了什么?为什么我需要它来使这项工作?

3 个答案:

答案 0 :(得分:10)

这是monomorphism restriction在起作用。 ab的类型默认为Integer,显然不能与/一起使用,因为它仅适用于Fractional类型。

您可以在定义ab时添加类型注释来解决此问题:

> let a = 5 :: Double
> let b = 2 :: Double
> a / b
2.5

或者你可以使用默认为Double的小数文字:

> let a = 5.0
> let b = 2.0
> a / b
2.5

如果将这三行一起进行类型检查,这将不会成为问题,因为它们将在已编译的模块中,或者如果您已输入

let a = 5; b = 2 in a / b

但是,当在GHCi中单独输入时,它们会一次一个地进行类型检查,因此在评估let a = 5选择Integer时应用的默认值是因为此时{{1}的唯一约束是a。它不知道我们需要Num约束,以便稍后使用Fractional

答案 1 :(得分:7)

Prelude> :t 5 / 2            -- The type is inferred to be a fractional
5 / 2 :: Fractional a => a
Prelude> :t (/)              -- ...because the type of (/)
(/) :: Fractional a => a -> a -> a
Prelude> let x = 5
Prelude> let y = 2
Prelude> :t x                -- In GHC there are addditional type defaulting rules
x :: Integer                 -- Instead of Num a => a, a lone integral is typed as `Integer`
Prelude> :t y
y :: Integer
Prelude> :i Fractional       -- Notice that 'Integer' is not an instance of 'Fractional'
class Num a => Fractional a where
  (/) :: a -> a -> a
  recip :: a -> a
  fromRational :: Rational -> a
    -- Defined in `GHC.Real'
instance Fractional Float -- Defined in `GHC.Float'
instance Fractional Double -- Defined in `GHC.Float'

简而言之? GHCi类型 - 将您的let-bound变量默认为Integer,其中没有Fractional个实例(因为Integer不是分数)。在通过ghc编译的Haskell程序中,类型将统一。

编辑:我应该补充一点,我想说明如何将let x = 4推断为Double,它是在更大的背景下,而不是GHCi。在回应Hammar的回答时,它不仅仅是单态,而且还与类型默认有关。 {GH}编译函数中ab可以单态地Double,但由于单态限制和逐行类型推断的组合我们无法得到x :: Num a => ax :: Double - 两者都符合您的需求。

答案 2 :(得分:2)

正如其他人所说,这是Monomorphism Restriction的错误。我没有注意像(a :: Double) / (b :: Double)这样的所有类型,而是更容易将其关闭:

Prelude> :set -XNoMonomorphismRestriction
Prelude> let a = 5
Prelude> let b = 2
Prelude> a / b
2.5

(您可以在.ghci file中保存:set操作,这样您就不需要每次都写一次了。