2017-01-30 16 views
1

То, что я сейчас пытаюсь сделать, это создать тип, который называется Value:Matching Ожидаемый тип с фактическим типом

data Value = Num Int 
      | Sum Int Int 
      | Dif Int Int 
      | Neg Int 
       deriving (Eq) 

, с которым я хочу реализовать функцию Eval:

eval :: Value -> Int 
eval (Num x) = x 
eval (Sum x y) = x + y 
eval (Dif x y) = x - y 
eval (Neg x) = -x 

Мои ожидаемые результаты должно быть:

eval $ Dif (Sum (Num 3) (Num 6)) (Neg 4) 
> 13 

С моим текущим кодом я могу проверить каждого оператора на них s и они функционируют.

eval (Dif 3 4) 
>-1 

Проблема возникает, когда я пытаюсь выполнить вложенные операции в планируемом входе выше, как я тогда получаю ошибку:

"Couldn't match expected type Int with actual type Value "

Я пытаюсь понять эту проблему, как я думал, что моя операция должен вернуть Int, и поскольку мои Value типа принимают Int, следующая операция должна иметь ожидаемый тип. Я тестировал различные входы, чтобы увидеть, что моя текущая функция Eval фактически делает и обнаружил, что, если я

eval (Dif (eval (Sum 3 5)) 4) 
>4 

я получаю ожидаемый результат. Что я здесь делаю неправильно?

+0

Почему вы пытаетесь поставить «Значение» во что-то, что принимает «Int»? 'Sum (Num 1) (Num 2)' не работает, потому что 'Num 1 :: Value', а' Sum' ожидает 'Int'. – AJFarmar

+1

Помимо правильного ответа, вы можете посмотреть в make 'Value' экземпляр' Num' - таким образом вы можете написать '1 :: Value'. – Alec

+1

Я полностью забыл, что на самом деле я принимаю значения типа; Я был в неправильном мышлении AJFarmer (я буду обвинять его в отсутствии сна). Мой пост был отредактирован, но я новичок в Haskell, поэтому я уступаю простым ошибкам. Спасибо за отзыв Алек! – Sinsarii

ответ

6
data Value = Num Int 
      | Sum Int Int 
      | Dif Int Int 
      | Neg Int 

Здесь вы указали, что Value конструкторы работают только на Int значений, например, Neg имеет тип Int -> Value. Поэтому вы не можете написать что-то вроде Neg (Neg 1) или Sum (Num 1) (Num 2), потому что вы пытаетесь использовать тегированный Value, где ожидается непомеченный Int. В Lisp было бы так, как если бы вы прошли (Num . 1), когда функция ожидает только 1.

Вы можете изменить определение вашего типа принять Value:

data Value = Num Int 
      | Sum Value Value 
      | Dif Value Value 
      | Neg Value 

Теперь это представляет выражения, где Num является буквальным Int но другие конструкторы работают на Value с. Затем изменяется функция eval:

eval :: Value -> Int 
eval (Num x) = x 
eval (Sum x y) = eval x + eval y 
-- ... 
+1

Спасибо за это! Я просто перечитал раздел и понял, что я сделал. Ваше объяснение было совершенным, хотя, спасибо! – Sinsarii