let e_app f args =
  if not (simpl()) then Tapp(f,args)
  else
    match f , args with
      | "neg_int" , [ Tapp"neg_int" , [a] ) ] -> a
      | "neg_real" , [ Tapp"neg_real" , [a] ) ] -> a
      | "neg_int" , [ Tconst (ConstInt a) ] ->
          i_apply Big_int.minus_big_int a
      | "add_int" , [ Tconst (ConstInt a) ; Tconst (ConstInt b) ] ->
          i_compute Big_int.add_big_int a b
      | "sub_int" , [ Tconst (ConstInt a) ; Tconst (ConstInt b) ] ->
          i_compute Big_int.sub_big_int a b
      | "mul_int" , [ Tconst (ConstInt a) ; Tconst (ConstInt b) ] ->
                  i_compute Big_int.mult_big_int a b
      | "add_int" , [ Tconst (ConstInt "0") ; x ] -> x
      | "add_int" , [ x ; Tconst (ConstInt "0") ] -> x
      | "sub_int" , [ x ; Tconst (ConstInt "0") ] -> x
      | "mul_int" , [ Tconst (ConstInt "1") ; x ] -> x
      | "mul_int" , [ x ; Tconst (ConstInt "1") ] -> x
      | "mul_int" , [ (Tconst (ConstInt "0")) as z ; _ ] -> z
      | "mul_int" , [ _ ; (Tconst (ConstInt "0")) as z ] -> z
      | "add_int" , [ b ; Tapp("sub_int",[a;c]) ] when eq_terms b c -> a ;
      | "add_int" , [ Tapp("sub_int",[a;b]) ; c ] when eq_terms b c -> a
      | "sub_int" , [ Tapp("add_int",[a;b]) ; c ] when eq_terms b c -> a
      | "encode" , [ Tapp("decode" , [ a ; fmt ]) ; fmt' ] when eq_terms fmt fmt' -> a
      | "decode" , [ Tapp("encode" , [ a ; fmt ]) ; fmt' ] when eq_terms fmt fmt' -> a
      | "as_int" , [Tapp(fmt,[]) ; Tconst(ConstInt z)] -> as_int_format fmt z
      | f , [Tconst(ConstInt z)] -> as_int f z 
      |  f , [Tapp(g,[d])] -> coercion f g d
      | _ -> Tapp (f, args)