letrec eval program = 
  let exp = fst program in 
    let env = snd program in 
      if equalS (fst exp) "const" 
        then snd exp  
      else if equalS (fst exp) "var"
      then 
          letrec lookupVar tup =
            let var = fst tup in
            let env = snd tup in
            if equalS (fst (fst env)) "END"
                then "Error: Unbound variable"
                else if equalS var (fst (fst env)) 
                    then snd (fst env) 
                    else lookupVar [var, snd env]
          in lookupVar [snd exp, env]
      else if equalS (fst exp) "cond"
        then 
          let e1 = fst (snd exp) in 
          let e2 = fst (snd (snd exp)) in 
          let e3 = snd (snd (snd exp)) in 
          let cond = eval [e1, env] in
          if isValBool cond 
            then if equalB (eval [e1,env]) True 
              then eval [e2,env] 
              else eval [e3,env]
          else "Error: Non boolean condition"
      else if equalS (fst exp) "lambda"
        then 
          let var = fst (snd exp) in 
          let e = snd (snd exp) in
          letrec f argExp = eval [e, [[var, argExp], env]] in 
          f
      else if equalS (fst exp) "app"
        then 
          let e1 = fst (snd exp) in
          let e2 = snd (snd exp) in 
          let v1 = eval [e1, env] in
          if isValFun v1 then v1 (eval [e2, env])
          else "Error: Non function application"
    else if equalS (fst exp) "letrec"
      then 
        let fun = (fst (fst (snd exp))) in 
        let var = (snd (fst (snd exp))) in
        let body = (fst (snd (snd exp))) in
        let e = snd (snd (snd exp)) in
        letrec recEnv x = [[fun, letrec f arg = eval [body, [[var, arg], (recEnv x)]] in f], env] in eval [e, (recEnv 0)]
      else "Error"
in eval 
[
  ["letrec", [["loop","x"],[["app", [["var", "loop"],["var", "x"]]], ["letrec", [["test", "x"], [["letrec", [["innerTest", "y"], [["var", "x"], ["var", "innerTest"]]]], ["app", [["app", [["var", "test"], ["const", 42]]], ["app", [["var", "loop"], ["const", 0]]]]]]]]]]]
,
[
  ["succ", \x -> succ x],
  [["minus", \x -> \y -> minus x y],
  [["equal", \x -> \y -> equal x y],
  [["add", \x -> \y -> add x y],
  [["END", False], False]]]]]
]

