4

在 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 发生了什么?为什么我需要它来完成这项工作?

4

3 回答 3

10

这是工作中的单态性限制a和的类型b默认为Integer,显然不能与它一起使用,/因为它只适用于Fractional类型。

您可以通过在定义aand时添加类型注释来解决此问题b

> 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因为此时唯一的约束aNum. 它不知道Fractional我们以后使用它所需的约束/

于 2013-04-26T20:27:49.123 回答
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实例(因为Integers 不是分数)。在通过 ghc 编译的 Haskell 程序中,类型将统一。

编辑:我应该补充一点,我想注意如何let x = 4在更大的上下文中推断出 Double,而不是在 GHCi 上。作为对 Hammar 的回答,这不仅仅是单态性,还与类型默认有关。 a并且b可以是单态Double的,就像在 GHC 编译的函数中一样,但是由于单态限制和逐行类型推断的组合,我们无法获得其中任何一个x :: Num a => ax :: Double- 两者都适合您的需求。

于 2013-04-26T20:28:34.870 回答
2

正如其他人所指出的,这是Monomorphism Restriction的错误。(a :: Double) / (b :: Double)我发现关闭它更容易,而不是注释所有类型:

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

(你可以将:set动作保存在你的.ghci 文件中,所以你不需要每次都写)

于 2013-04-26T22:05:36.333 回答