【问题标题】:Error: "No instances for (x)..."错误:“没有 (x) 的实例...”
【发布时间】:2023-03-11 08:38:01
【问题描述】:

Thompson 的练习 14.16-17 要求我将乘法和(整数)除法运算添加到表示简单算术语言的 Expr 类型,然后定义函数 showeval(计算 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 的实例。

【问题讨论】:

    标签: haskell types instances


    【解决方案1】:

    嗯,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)
    

    这个只允许你添加Expressions,如果它们包含纯数字。我很确定你不想要那个。 您想添加 任意表达式 并且您已经有了相应的语法。只是

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

    这使您可以使用完全正常的语法编写(L 1) + (L 2)。同样,eval 不应该只是减少表达式,而是产生一个数字,因此具有 eval :: Expr -> Integer 类型。除法很简单

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

    这是定义的,因为您只是将 数字相除

    【讨论】:

    • 所以函数'div'不需要重载Real或Enum的某些函数,但是作为Integral的实例需要是Real和Enum的实例?好的,谢谢。
    • 不,div 仅可用作类Integral 的实例方法,因此要求您的类型也为RealEnum。但请阅读我编辑的答案......你可能不想要那个。
    • 好吧,我知道我可以在 Num Expr 的实例声明中将运算符 c 定义为 (c) = (:c),并且 'eval' 应该返回一个 Int;但这个练习比让 eval 返回 Expr 类型的值更无聊。如果这不是你的意思,那么也许我“真的”把我的类型搞砸了。
    • 我不太明白您对运算符 c 的意思,但只需定义 eval :: Expr -> Int,我很确定它会起作用 ;)
    • 我想我很密集,我刚刚意识到你在编辑中的意思,虽然我不明白为什么我的类型“搞砸了”。感谢您的帮助!
    猜你喜欢
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多