错误:“没有 (x)... 的实例”

发布于 2024-09-11 09:51:51 字数 1696 浏览 6 评论 0原文

Thompson 的练习 14.16-17 要求我将乘法和(整数)除法运算添加到 Expr 类型(它代表一种简单的算术语言),然后定义函数 showeval< /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 ExprReal 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

噩梦成真你也成魔 2024-09-18 09:51:52

嗯,这就是 Integral 类型类的定义方式。有关信息,您可以在 GHCi 中键入 :i Integral

您会明白

class (Real a, Enum a) => Integral a where ...

,这意味着任何应该是 Integral 的类型 a 都必须首先是 RealEnum 。这就是生活。


请注意,也许您的类型有点混乱。看一下

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 Num Expr where
  (+) = (:+)
  (-) = (:-)
  -- ...

这允许您使用完全正常的语法编写 (L 1) + (L 2) 。同样,eval 不应该只简化表达式,还应该生成一个数字,因此具有 eval :: Expr -> 类型。整数。 问题来说很简单,因为您只需除数字

eval (a :/ b) = (eval a) `div` (eval b)

除法对于定义的

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

class (Real a, Enum a) => Integral a where ...

which means any type a that should be Integral has to be Real and Enum first. C'est la vie.


Note that maybe you've got your types messed up quite a bit. Take a look at

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)

This just allows you to add Expressions 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

instance Num Expr where
  (+) = (:+)
  (-) = (:-)
  -- ...

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 type eval :: Expr -> Integer. Division is simple for that matter

eval (a :/ b) = (eval a) `div` (eval b)

which is defined since you just divide numbers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文