表达式'pi * r'中没有(Fractional Int)的实例* r'`

时间:2015-07-09 06:57:29

标签: haskell

我试图制作一个非常简单的区域计划:

type Point = (Int, Int)
data Figure = Rect Point Point | Circ Point Int
area (Rect (x1,y1) (x2,y2)) = (x2 - x1) * (y1 - y2)
area (Circ _ r) = pi * r'^2 where r' = fromIntegral r

当我手动将其键入ghci时,它没有错误并按预期工作。

但是,编译此程序会产生以下错误:

No instance for (Floating Int) arising from a use of `pi'
In the first argument of `(*)', namely `pi'
In the expression: pi * r' ^ 2
In an equation for `area':
    area (Circ _ r)
      = pi * r' ^ 2
      where
          r' = fromIntegral r

这里发生了什么?

3 个答案:

答案 0 :(得分:5)

Always use type signatures。在这种情况下,您显然希望结果为Double。一旦明确说明,编译器错误将变得非常清楚,以便理解。

目前尚不清楚错误的原因是:从第一个条款

area (Rect (x1,y1) (x2,y2)) = (x2 - x1) * (y1 - y2)

编译器推断area的结果类型为(x2 - x1) * (y1 - y2),其类型与xⱼyⱼ本身相同:Int。当编译器检查第二个子句时,它会找到fromIntegral'。这可以产生任何数字类型,包括Int,所以这里没问题。因此推断乘法也是积分的。但这意味着pi也需要Int,这显然是无稽之谈!

使用正确的签名,

area :: Figure -> Double

编译器将在第一个子句停止,正确地抱怨IntDouble不匹配。你需要另一个fromIntegral

答案 1 :(得分:5)

问题

函数的第一个等式具有返回类型Int,但第二个等式的返回类型为Floating a => a。现在,编译器尝试将aInt统一,但Int不是Floating的实例(正如编译器告诉您的那样),因此编译失败并带有类型错误。

为什么ghci接受它。

当您将这些行键入ghci时,它不会将area的第二个等式视为函数定义的扩展,而是覆盖它。 因此,如果您尝试在area的ghci中使用Rect,则会失败。

答案 2 :(得分:5)

您没有收到ghci中的错误,因为您覆盖了area Rect的定义。

如果你这样做,你会收到错误:

let area (Rect (x1,y1) (x2,y2)) = (x2 - x1) * (y1 - y2); area (Circ _ r) = pi * r'^2 where r' = fromIntegral r

这是您的代码(已启用-Wall):

Prelude> :set -Wall
Prelude> type Point = (Int, Int)
Prelude> data Figure = Rect Point Point | Circ Point Int
Prelude> let area (Rect (x1,y1) (x2,y2)) = (x2 - x1) * (y1 - y2)

<interactive>:5:5: Warning:
    Pattern match(es) are non-exhaustive
    In an equation for ‘area’: Patterns not matched: Circ _ _
Prelude> let area (Circ _ r) = pi * r'^2 where r' = fromIntegral r

<interactive>:6:5: Warning:
    This binding for ‘area’ shadows the existing binding
      defined at <interactive>:5:5

<interactive>:6:5: Warning:
    Pattern match(es) are non-exhaustive
    In an equation for ‘area’: Patterns not matched: Rect _ _

<interactive>:6:30: Warning:
    Defaulting the following constraint(s) to type ‘Integer’
      (Integral b0) arising from a use of ‘^’ at <interactive>:6:30
      (Num b0) arising from the literal ‘2’ at <interactive>:6:31
    In the second argument of ‘(*)’, namely ‘r' ^ 2’
    In the expression: pi * r' ^ 2
    In an equation for ‘area’:
        area (Circ _ r)
          = pi * r' ^ 2
          where
              r' = fromIntegral r

一般来说,使用-Wall始终是个好主意。