data Exp = Num Int | Add Exp Exp | Sub Exp Exp | Mul Exp Exp | Div Exp Exp
 deriving Show

eval :: Exp -> Int
eval (Num 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 e2) = eval e1 `div` eval e2

-- optional integers
data OptInt = None | Some Int
 deriving Show

-- pass through failure
try :: OptInt -> (Int -> OptInt) -> OptInt
try None     _ = None
try (Some n) f = f n

-- safe evaluation
eval' :: Exp -> OptInt
eval' (Num n) = Some n
eval' (Add e1 e2)
  = try (eval' e1) (\n1 -> try (eval' e2) (\n2 -> Some (n1+n2)))
eval' (Sub e1 e2)
  = try (eval' e1) (\n1 -> try (eval' e2) (\n2 -> Some (n1-n2)))
eval' (Mul e1 e2)
  = try (eval' e1) (\n1 -> try (eval' e2) (\n2 -> Some (n1*n2)))
eval' (Div e1 e2)
  = try (eval' e1) (\n1 -> try (eval' e2)  -- division by 0 leads None
                            (\n2 -> if n2==0 then None else Some (n1`div`n2)))

