Ошибка: нет экземпляров для (x)

В упражнении 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

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

Однако я сталкиваюсь с проблемами, когда пытаюсь реализовать разделение. Я не понимаю сообщение об ошибке, которое я получаю, когда пытаюсь скомпилировать следующее:

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.


person danportin    schedule 28.07.2010    source источник


Ответы (1)


Так определяется класс типов 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)

Это просто позволяет вам добавлять Expressions, если они переносят простые числа. Я почти уверен, что ты этого не хочешь. Вы хотите добавить произвольные выражения, и у вас уже есть синтаксис для этого. Это просто

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

Это позволяет вам писать (L 1) + (L 2) с совершенно нормальным синтаксисом. Точно так же eval должен не просто сокращать выражения, но выдавать число и, следовательно, иметь тип eval :: Expr -> Integer. Деление в этом отношении простое

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

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

person Dario    schedule 28.07.2010
comment
Таким образом, функция 'div' не требует перегрузки определенных функций для Real или Enum, но для того, чтобы быть экземпляром Integral, необходимо быть экземпляром Real и Enum? Хорошо спасибо. - person danportin; 28.07.2010
comment
Нет, div доступен только как метод экземпляра класса Integral и поэтому требует, чтобы ваш тип также был Real и Enum. Но прочтите мой отредактированный ответ ... вы, вероятно, этого не хотите. - person Dario; 28.07.2010
comment
Что ж, я знаю, что я мог бы определить оператор c как (c) = (: c) в объявлении экземпляра для Num Expr, и что «eval» должен возвращать Int; но это упражнение было скучнее, чем когда eval возвращает значение типа Expr. Если, однако, вы имеете в виду не это, то, возможно, я действительно испортил свой типаж. - person danportin; 28.07.2010
comment
Я не совсем понимаю, что вы имеете в виду со своим оператором c, просто определите eval :: Expr -> Int, и я почти уверен, что это сработает;) - person Dario; 28.07.2010
comment
Думаю, я тупой, я только что понял, что вы имели в виду в своем редактировании, хотя я не понимаю, почему у меня мои типы "испорчены". Спасибо за вашу помощь! - person danportin; 28.07.2010