Несоответствие типа деления haskell?

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

Вот код:

data Value e = OK e | Error String deriving (Eq)

-- assuming we know how to type e can be shown, i.e. Show e, then
-- we know how to show a Value e type
instance (Show e) => Show (Value e) where
    show (OK x) = (show x)
    show (Error s) = "ERROR: " ++ s

type Token = String
type Result = Value Int
type Intermediate = [ (Value Int) ]

-- an algebra is a things that knows about plus and times
class Algebra a where
    plus :: a -> a -> a
    times :: a -> a -> a
    subtraction :: a -> a -> a
    division :: a -> a-> a

-- assuming that we know how to + and * things of type e, (i.e.
-- we have Num e, then we have algebra's over Value e 
instance (Num e) => Algebra (Value e) where
    plus (OK x) (OK y) = (OK (x+y))
    times (OK x) (OK y) = (OK (x*y))
    subtraction (OK x) (OK y) = (OK (x-y))
    division (OK x) (OK 0) = (Error "div by 0")
    division (OK x) (OK y) = (OK (x `div` y))   <-- this is line 44 that it complains about

Вот ошибка, когда я пытаюсь запустить программу через ghci test.hs

test.hs:44:34:  
    Could not deduce (Integral e)  
      from the context (Algebra (Value e), Num e)  
      arising from a use of `div' at test.hs:44:34-42  
    Possible fix:  
      add (Integral e) to the context of the instance declaration  
    In the first argument of `OK', namely `(x `div` y)'  
    In the expression: (OK (x `div` y))  
    In the definition of `division':  
        division (OK x) (OK y) = (OK (x `div` y))  

Для этого есть еще код, я думал, что оставлю его для ясности, но я всегда могу отредактировать его, если в противном случае это неясно.


person Jean-Bernard Pellerin    schedule 06.12.2010    source источник
comment
Это не должно быть вопросом..   -  person Omnipotent    schedule 26.04.2011


Ответы (2)


div :: (Integral a) => a -> a -> a
(/) :: (Fractional a) => a -> a -> a

Num a не подразумевает ни Integral a, ни Fractional a (хотя, конечно, применяется обратное). Если вы хотите использовать div, вам придется предоставить что-то не менее ограничивающее, чем контекст Integral a.

person ephemient    schedule 06.12.2010
comment
... Я не могу поверить, что потратил на это так много времени, я искал во всех неправильных местах, пытаясь ограничить типы, где используется e. Ваше указание на Num привело меня к instance (Num e) =>, возможно, единственной строке кода, которую я не подумал изменить во время тестирования... Спасибо. - person Jean-Bernard Pellerin; 06.12.2010

div работает только со значениями Integral (только Int или Integer в стандартной версии Prelude). Float и Double поддерживают деление с оператором /, но корень вашей проблемы в том, что класс типов Num на самом деле не требует операции деления любого рода.

В этом есть смысл — существует множество коллекций чисел, которые мы могли бы захотеть сделать экземплярами Num, где умножение необратимо — операция деления была бы практически бессмысленной.

person Anon.    schedule 06.12.2010