def is_variable(x): return is_string(x)
def is_same_variable(v1, v2):
    return is_variable(v1) and is_variable(v2) and v1 == v2
def is_sum(x):
    return is_pair(x) and head(x) == "+"
def make_sum(a1, a2): return llist("+", a1, a2)

def make_product(m1, m2): return llist("*", m1, m2)
def addend(s): return head(tail(s))
def augend(s): return head(tail(tail(s)))
def is_product(x):
    return is_pair(x) and head(x) == "*"
def multiplier(s): return head(tail(s))
def multiplicand(s): return head(tail(tail(s)))
def deriv(exp, variable):
    return (0
            if is_number(exp)
            else (1 if is_same_variable(exp, variable) else 0)
            if is_variable(exp)
            else make_sum(deriv(addend(exp), variable),
                          deriv(augend(exp), variable))
            if is_sum(exp)
            else make_sum(make_product(multiplier(exp),
                                       deriv(multiplicand(exp), 
                                             variable)),
		          make_product(deriv(multiplier(exp), 
                                             variable),
                                       multiplicand(exp)))
            if is_product(exp)
            else error("unknown expression type -- deriv", exp))
print(head(tail(deriv(llist("*", "x", "y"), "x"))))

# expected: [ '*', [ 'x', [ 0, None ] ] ]
