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

时间:2010-07-28 12:13:26

标签: haskell types instances

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

首先,我不知道为什么为数据类型定义div为什么Expr要求我定义Enum ExprReal Expr的实例。

1 个答案:

答案 0 :(得分:3)

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

你会得到

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

这意味着任何a类型Integral必须首先为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)

这个只允许你添加Expr个会话,如果它们包含普通数字。我很确定你不想那样。 您想要添加任意表达式,并且您已经有了这个语法。这只是

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

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

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

这是定义的,因为你只需要划分数字