I will talk about functions more in-class.
Start with functions of just one argument.
You'll need to extend your parser to allow the definition of functions. They'll only appear (as definitions) on the right-hand side of a with binding. You will also need to find places where functions are applied, and in those cases, build a fun-app data structure. So, in our interpreter, we will be looking for fun-def structures (which are function definitions) and fun-app structures (which are function applications).
Once you are parsing functions into fun-def structures, you'll then want to extend your interpreter to build a closure whenever a function is found.
Lastly, you'll need to implement function application in your interpreter. This is not conceptually difficult: you have done it already for binops. Remember, a binop was a function, and you simply pulled the op out and applied it to the arguments (the lhs and rhs). That said, careful consideration needs to be given to the environment in which you will apply your function.
A big part of writing an interpreter is managing the environment, or (if you prefer) the bindings of values to names.