错误:“没有 (x)... 的实例”
Thompson 的练习 14.16-17 要求我将乘法和(整数)除法运算添加到 Expr 类型(它代表一种简单的算术语言),然后定义函数 show 和 eval< /em>(计算 Expr 类型的表达式)为 Expr。
我的解决方案适用于除除法之外的每个算术运算:
data Expr = L Int
| Expr :+ Expr
| Expr :- Expr
| Expr :* Expr
| Expr :/ Expr
instance Num Expr where
(L x) + (L y) = L (x + y)
(L x) - (L y) = L (x - y)
(L x) * (L y) = L (x * y)
instance Eq Expr where
(L x) == (L y) = x == y
instance Show Expr where
show (L n) = show n
show (e1 :+ e2) = "(" ++ show e1 ++ " + " ++ show e2 ++ ")"
show (e1 :- e2) = "(" ++ show e1 ++ " - " ++ show e2 ++ ")"
show (e1 :* e2) = "(" ++ show e1 ++ " * " ++ show e2 ++ ")"
show (e1 :/ e2) = "(" ++ show e1 ++ " / " ++ show e2 ++ ")"
eval :: Expr -> Expr
eval (L n) = L n
eval (e1 :+ e2) = eval e1 + eval e2
eval (e1 :- e2) = eval e1 - eval e2
eval (e1 :* e2) = eval e1 * eval e2
例如,
*Main> (L 6 :+ L 7) :- L 4
((6 + 7) - 4)
*Main> it :* L 9
(((6 + 7) - 4) * 9)
*Main> eval it
81
it :: Expr
但是,当我尝试实现除法时,我遇到了问题。我不明白当我尝试编译以下内容时收到的错误消息:
instance Integral Expr where
(L x) `div` (L y) = L (x `div` y)
eval (e1 :/ e2) = eval e1 `div` eval e2
这是错误:
Chapter 14.15-27.hs:19:9:
No instances for (Enum Expr, Real Expr)
arising from the superclasses of an instance declaration
at Chapter 14.15-27.hs:19:9-21
Possible fix:
add an instance declaration for (Enum Expr, Real Expr)
In the instance declaration for `Integral Expr'
首先,我不知道为什么为数据类型 Expr 定义 div
需要我定义 Enum Expr
或 Real Expr
的实例。
Exercise 14.16-17 in Thompson asks me to add the operations of multiplication and (integer) division to the type Expr, which represents a simple language for arithmetic, then define the functions show and eval (evaluates an expression of type Expr) for Expr.
My solution works for each arithmetic operation except division:
data Expr = L Int
| Expr :+ Expr
| Expr :- Expr
| Expr :* Expr
| Expr :/ Expr
instance Num Expr where
(L x) + (L y) = L (x + y)
(L x) - (L y) = L (x - y)
(L x) * (L y) = L (x * y)
instance Eq Expr where
(L x) == (L y) = x == y
instance Show Expr where
show (L n) = show n
show (e1 :+ e2) = "(" ++ show e1 ++ " + " ++ show e2 ++ ")"
show (e1 :- e2) = "(" ++ show e1 ++ " - " ++ show e2 ++ ")"
show (e1 :* e2) = "(" ++ show e1 ++ " * " ++ show e2 ++ ")"
show (e1 :/ e2) = "(" ++ show e1 ++ " / " ++ show e2 ++ ")"
eval :: Expr -> Expr
eval (L n) = L n
eval (e1 :+ e2) = eval e1 + eval e2
eval (e1 :- e2) = eval e1 - eval e2
eval (e1 :* e2) = eval e1 * eval e2
E.g.,
*Main> (L 6 :+ L 7) :- L 4
((6 + 7) - 4)
*Main> it :* L 9
(((6 + 7) - 4) * 9)
*Main> eval it
81
it :: Expr
However, I am running into problems when I try to implement division. I don't understand the error message I receive when I try to compile the following:
instance Integral Expr where
(L x) `div` (L y) = L (x `div` y)
eval (e1 :/ e2) = eval e1 `div` eval e2
This is the error:
Chapter 14.15-27.hs:19:9:
No instances for (Enum Expr, Real Expr)
arising from the superclasses of an instance declaration
at Chapter 14.15-27.hs:19:9-21
Possible fix:
add an instance declaration for (Enum Expr, Real Expr)
In the instance declaration for `Integral Expr'
In the first place, I have no idea why defining div
for the data type Expr requires me to define an instance of Enum Expr
or Real Expr
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嗯,这就是 Integral 类型类的定义方式。有关信息,您可以在 GHCi 中键入
:i Integral
。您会明白
,这意味着任何应该是
Integral
的类型a
都必须首先是Real
和Enum
。这就是生活。请注意,也许您的类型有点混乱。看一下
仅允许您添加
表达式
会话(如果它们包含普通数字)。我很确定你不希望这样。您想要添加任意表达式,并且您已经有了相应的语法。只是
这允许您使用完全正常的语法编写
(L 1) + (L 2)
。同样,eval
不应该只简化表达式,还应该生成一个数字,因此具有eval :: Expr -> 类型。整数
。 问题来说很简单,因为您只需除数字。除法对于定义的
Well, that's the way the
Integral
typeclass is defined. For information, you can e.g. just type:i Integral
into GHCi.You'll get
which means any type
a
that should beIntegral
has to beReal
andEnum
first. C'est la vie.Note that maybe you've got your types messed up quite a bit. Take a look at
This just allows you to add
Expr
essions if they wrap plain numbers. I'm pretty sure you don't want that.You want to add arbitrary expressions and you already have a syntax for this. It's just
This allows you to write
(L 1) + (L 2)
with perfectly normal syntax. Likewise,eval
should not just reduce expressions but yield a number, and therefore have the typeeval :: Expr -> Integer
. Division is simple for that matterwhich is defined since you just divide numbers.