rendered paste body
module Blatt04 where
data Expr =
Const Int
| Add Expr Expr -- a+b
| Sub Expr Expr -- a-b
| Mul Expr Expr -- a*b
| Div Expr Expr -- a/b (ganzzahlige Division)
| Neg Expr -- -a
deriving (Eq, Show)
-- 1.1
{-
Hier gibt es eigentlich nicht viel zu erklären...
Division durch 0 ist nicht definiert und Negation entspricht der Multiplikation
mit (-1) .
-}
eval :: Expr -> Int
eval (Const n) = n
eval (Add e1 e2) = (eval e1)+(eval e2)
eval (Sub e1 e2) = (eval e1)-(eval e2)
eval (Mul e1 e2) = (eval e1)*(eval e2)
eval (Div e1 (Const 0)) = error "Division durch 0 nicht definiert"
eval (Div e1 e2) = (eval e1) `div` (eval e2)
eval (Neg e1) = eval (Mul (Const (-1)) e1)
-- 1.2
{-
Wir vereinbaren vorab:
Bei Negation und negativen Konstanten/Zahlen wird immer geklammert um klar zu machen,
dass eine negative Zahl gemeint ist bzw. um zu vermeiden, dass zwei Operatoren
nebeneinanderstehen. (Also z.B. nicht: 5 * -9, sondern 5 * (-9)
Ansonsten gelten die "normalen" Prioritäten wie Punkt- vor Strichrechnung und, dass
Ausdrücke von links nach rechts ausgewertet werden.
( 3*4/5*6 entspricht ((3*4)/5)*6 )
-}
getFormula :: Expr -> String
-- um den ganzen Term muss keine Klammer gemacht werde
-- immer wenn evtl. Punkt- vor Strichrechnung gilt, wird der "innere" Ausdruck
-- mit getKlammerFormula ausgwertet
getFormula (Const n) = if n<0 then "(" ++ show n ++ ")" else show n
getFormula (Add e1 e2) = getFormula e1 ++ "+" ++ getFormula e2
getFormula (Sub e1 e2) = getFormula e1 ++ "-" ++ getKlammerFormula e2
getFormula (Mul e1 e2) = getKlammerFormula e1 ++ "*" ++ getKlammerFormula e2
-- Außer wenn hinter dem "/" nur eine Konstante bzw. eine Negation steht, muss bei der
-- Ganzzahldivison auf jeden Fall die 2. Expression eingeklammert werden, da ansonsten fehlerhaft gerechnet würde
-- z.B. korrekt: 3*8 `div` (2*7) = 1 , falsch: 3*8 `div` 2*7 = 84
getFormula (Div e1 (Const n)) = getKlammerFormula e1 ++ "/" ++ getFormula (Const n)
getFormula (Div e1 (Neg e2)) = getKlammerFormula e1 ++ "/" ++ getFormula (Neg e2)
getFormula (Div e1 e2) = getKlammerFormula e1 ++ "/" ++ "(" ++ getFormula e2 ++ ")"
-- Vereinbarung zur Negation: siehe oben
getFormula (Neg (Const n)) = "(-" ++ getFormula (Const n)++ ")"
getFormula (Neg e1) = "(-("++ getFormula e1 ++ "))"
-- evtl. muss je nach Vorrang der Operatoren eine Klammer um einen inneren Term gemacht werden
getKlammerFormula :: Expr -> String
getKlammerFormula (Const n) = getFormula (Const n) -- keine Klammerung notwendig
getKlammerFormula (Add e1 e2) = "(" ++ getFormula (Add e1 e2) ++ ")" -- Punkt- vor Strichrechnung => Klammer notwending
getKlammerFormula (Sub e1 e2) = "(" ++ getFormula (Sub e1 e2) ++ ")" -- Punkt- vor Strichrechnung => Klammer notwending
getKlammerFormula (Mul e1 e2) = getFormula (Mul e1 e2) -- keine Klammerung notwendig
getKlammerFormula (Div e1 e2) = getFormula (Div e1 e2) -- keine Klammerung notwendig
getKlammerFormula (Neg e1) = getFormula (Neg e1) -- keine Klammerung notwendig