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