(*
  *)

val int2Str = Int.toString;

val tempCtr = ref 0;
fun newtemp () =
  let val n = !tempCtr
  in (tempCtr := n+1; int2Str n ) end;



(* ************************************ *)

datatype exp
  =  Plus of exp  * exp
  |  Times of exp * exp
  |  Num  of  int
  |  Var of string
  |  Assign of string * exp
  ;


fun mean x =
case x of
   Plus(x,y) => (mean x) + (mean y)
|  Times(x,y)  => (mean x) * (mean y)
|  Num n => n


(* *************************************** *)

fun mean2 x =
case x of
   Plus(x,y) =>
        let val (namex,codex) = (mean2 x)
            val (namey,codey) = (mean2 y)
            val new = newtemp()
        in (new, codex ^ codey ^
                 (new ^ " = " ^namex ^ " + " ^ namey))
        end
|  Times(x,y)  =>
       let val (namex,codex) = (mean2 x)
             val (namey,codey) = (mean2 y)
             val new = newtemp()
        in (new, codex ^ codey ^
                 (new ^ " = " ^namex ^ " * " ^ namey))
        end
|  Num n => let val new = newtemp()
            in (new, new ^" = "^(int2Str n)) end



(* *************************************** *)

exception NoSuchVar of string;

fun mean3 x env =
case x of
   Var s =>
      (case List.find (fn (x,v) => x=s) env of
         NONE => raise (NoSuchVar s)
       | SOME(_,v) => v)
|  Plus(x,y) => (mean3 x) env + (mean3 y) env
|  Times(x,y)  => (mean3 x) env * (mean3 y) env
|  Num n => n

(* ************************************* *)

fun update [] var value = [(var,value)]
  | update ((s,v)::xs) var value =
      if s=var then (s,value)::xs
               else (s,v)::(update xs var value);

fun mean4 x env =
case x of
   Var s =>
      (case List.find (fn (x,v) => x=s) env of
         NONE => raise (NoSuchVar s)
       | SOME(_,v) => (env,v))
|  Plus(x,y) =>
    let val (env2,x') = (mean4 x) env
        val (env3,y') = (mean4 y) env2
    in (env3,x' + y') end
|  Times(x,y)  =>
    let val (env2,x') = (mean4 x) env
        val (env3,y') = (mean4 y) env2
    in (env3,x' * y') end
|  Num n => (env,n)
|  Assign(x,exp) =>
    let val (env2,exp') = (mean4 exp) env
    in (update env x exp',exp') end;

(* 
*)