Ошибка: «Нет экземпляров для (x) ...» - PullRequest
1 голос
/ 28 июля 2010

Упражнение 14.16-17 в Томпсоне просит меня добавить операции умножения и (целочисленного) деления к типу Expr, который представляет простой язык для арифметики, затем определить функции show и eval (оценивает выражение типа 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'

Во-первых, я понятия не имею, почему определение div для типа данных Expr требует от меня определения экземпляра Enum Expr или Real Expr.

1 Ответ

3 голосов
/ 28 июля 2010

Ну, вот как определяется класс типов Integral.Для информации, например, вы можете просто набрать :i Integral в GHCi .

. Вы получите

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

, что означает любой тип a, который должен быть Integral должен быть Real и Enum первым.Такова жизнь.


Обратите внимание, что, возможно, у вас совсем немного перепутались ваши типы.Взгляните на

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)

, которое определено, поскольку вы просто делите числа .

...