我试图制作一个非常简单的区域计划:
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
这里发生了什么?
答案 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
编译器将在第一个子句停止,正确地抱怨Int
与Double
不匹配。你需要另一个fromIntegral
。
答案 1 :(得分:5)
函数的第一个等式具有返回类型Int
,但第二个等式的返回类型为Floating a => a
。现在,编译器尝试将a
与Int
统一,但Int
不是Floating
的实例(正如编译器告诉您的那样),因此编译失败并带有类型错误。
当您将这些行键入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
始终是个好主意。