plus  = lambda x,y: x+y
minus = lambda x,y: x-y
times = lambda x,y: x*y
div   = lambda x,y: x/y

def demo1():
  return [minus,
          [plus, 1, 2],
          [plus, 3, 4]
          ]

def demo2():
  return ['begin',
          ['set!', 
                   'a', [times, 2,10]],
          ['!','a']]


def get(key1,env):
  print env
  for key2,binding in env:
    if key1 == key2: return binding
  return None

def put(key1,new,env):
  
  out = []
  for key2,val in env:
    if key1==key2:
      val = new
    out += [(key2,val)]
    
  return out

def tval(x,env=[]):
  nump    = lambda z: isinstance(z, (int, long, float, complex))          
  listp   = lambda z: isinstance(z, list)
  stringp = lambda z: isinstance(z, str)
  simple  = lambda z: stringp(z) or nump(z)
  callp   = lambda z: hasattr(z, '__call__') 
  op      = lambda z: z[0]
  lhs     = lambda z: z[1]
  rhs     = lambda z: z[2]
  if simple(x):
    return x
  elif x[0] == 'begin':
    for y in x[1:]: out = tval(y,env)
    return out
  elif x[0] == 'set!':
    new = tval(x[2],env)
    env = put(x[1],new,env)
    return new
  elif x[0] == '!':
    return get(x[1],env)
  elif listp(x):
    left  = tval(lhs(x))
    right = tval(rhs(x))
    act   = op(x)
    return act(left,right)
  
print tval(demo2())


