#haskell
#haskell
Вопрос:
Я пытаюсь написать функцию, которая оценивает вложенный логический тип данных. Моя проблема возникает из-за сравнения типа данных внутри типа данных. Первые два (Lit и Or) компилируются нормально, но я не понимаю, как включить первый тип в функцию SecondExpr. Когда я набираю его, я чувствую, что выбираю самый длинный возможный путь, когда работает что-то более короткое.
Вот два типа данных.
data Expr = Val Int
| Add Expr Expr
| Sub Expr Expr
| Mul Expr Expr
| Div Expr Expr
| If SecondExpr Expr Expr
data SecondExpr = Lit Bool
| Or SecondExpr SecondExpr
| EqualTo Expr Expr
| LessThan Expr Expr
(Еще одна проблема, с которой я сталкиваюсь, — это создание примеров SecondExpr для тестирования, потому что концептуально я рассматриваю каждое выражение как 6 различных типов выражения. Это означает, что для каждого выражения Expr будут сотни стражей.)
Ниже приведен код на данный момент:
eval :: SecondExpr -> Bool
eval (Lit n) = n
eval (Or e1 e2)
| True amp;amp; True = True
| True amp;amp; False = True
| False amp;amp; True = True
| otherwise = False
eval (EqualTo e1 e2)
| (Add e1 e2) == (Add e1 e2) = True
| (Sub e1 e2) == (Sub e1 e2) = True
| (Mul e1 e2) == (Mul e1 e2) = True
| (Div e1 e2) == (Div e1 e2) = True
| otherwise = False
eval (LessThan e1 e2)
| (Add e1 e2) == (Add e1 e2) = True
| (Sub e1 e2) == (Sub e1 e2) = True
| (Mul e1 e2) == (Mul e1 e2) = True
| (Div e1 e2) == (Div e1 e2) = True
| otherwise = False
Это ошибка, которую я получаю:
* No instance for (Eq Expr) arising from a use of `=='
* In the expression: (Add e1 e2) == (Add e1 e2)
In a stmt of a pattern guard for
an equation for `eval':
(Add e1 e2) == (Add e1 e2)
In an equation for `eval':
eval (EqualTo e1 e2)
| (Add e1 e2) == (Add e1 e2) = True
| (Sub e1 e2) == (Sub e1 e2) = True
| (Mul e1 e2) == (Mul e1 e2) = True
| (Div e1 e2) == (Div e1 e2) = True
| otherwise = False
|
24 | | (Add e1 e2) == (Add e1 e2) = True
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Итак, я знаю, что мой синтаксис неправильный, но как вы заменяете выражение в функции выражения?
Комментарии:
1.
True amp;amp; True
то же самое, что и простоTrue
. Защитное выражение| True
всегда выполняется успешно; это все равно, что вообще не иметь защиты:eval (Or e1 e2) = True
.2. Мне неясно, для чего
SecondExpr
это нужно. Вы, вероятно, хотите, например.eval (Or e1 e2) = eval e1 || eval e2
вместо того, что вы написали, что является постояннымTrue
. ДляEqualTo
вам понадобитсяeval'
onExpr
для некоторого приравниваемого типа, затем простоeval (EqualTo e1 e2) = eval' e1 == eval' e2
(и вы можете увидеть, как легко адаптировать это дляLessThan
). Это также решает проблему комбинаторного взрыва, которую вы наблюдали, хотя, как я уже сказал, общий дизайн кажется сомнительным, но трудно быть более полезным без большего контекста.
Ответ №1:
Вам понадобятся две функции оценки:
evalNum :: Expr -> Int
и
evalBool :: SecondExpr -> Bool
Ни один из них не должен использовать никаких предохранителей ( | ...
).
Например, evalBool
будет выглядеть так:
evalBool (Lit n) = n
evalBool (Or e1 e2) = evalBool e1 || evalBool e2
evalBool (EqualTo e1 e2) = evalNum e1 == evalNum e2
evalBool (LessThan e1 e2) = evalNum e1 < evalNum e2
Подвыражения вычисляются рекурсивно с помощью соответствующих eval
функций, а результаты объединяются с использованием соответствующих операторов Haskell (таких как ||
, ==
, <
).
Реализация evalNum
оставлена в качестве упражнения для читателя.