{- CSci 556: Multiparadigm Programming
   Expressions
   Spring 2017 
   H. Conrad Cunningham

1234567890123456789012345678901234567890123456789012345678901234567890

2008-09-10: Scala code from _A Scala Tutorial for Java Programmers_
2012-03-06: Minor correction to Scala code
2017-03-29: First Haskell version; changed Const to Val, Sum to Add

-}

module ExprTreeCalculator
    (ExprTree, Name, Env, eval, derive, simplify)
where

type Name = String
type Env  = [(Name,Int)]

data ExprTree = Add ExprTree ExprTree
                | Var Name
                | Val Int
                deriving Show

eval :: ExprTree -> Env -> Int
eval (Add l r) env = eval l env + eval r env
eval (Var n)   env =
  case (lookup n env) of
    Just i  -> i
    Nothing -> error ("Undefined variable " ++ show n)
eval (Val v)   _   = v

derive :: ExprTree -> Name -> ExprTree
derive (Add l r) v = Add (derive l v) (derive r v)
derive (Var n)   v
  | v == n         = Val 1
derive _         _ = Val 0

simplify :: ExprTree -> ExprTree
simplify t@(Val _)               = t
simplify t@(Var _)               = t
simplify (Add (Val 0) r        ) = simplify r
simplify (Add l         (Val 0)) = simplify l
simplify (Add (Val x) (Val y))   = Val (x+y)

main =
  do
    let exp = Add (Add (Var "x") (Var "x")) (Add (Val 7) (Var "y"))
    let env = [("x",5), ("y",7)]
    putStrLn ("Expression: " ++ show exp) 
    putStrLn ("Evaluation with x=5, y=7: "   ++ show (eval exp env))
    putStrLn ("Derivative relative to x:\n " ++ show (derive exp "x"))
    putStrLn ("Derivative relative to y:\n " ++ show (derive exp "y"))


