Repeatedly allow the user to type a lambda expression, reduce it to its "ground form" and print the final result. You may choose the exact syntax to make the processing convenient, so long as it is not confusingly different from the various common forms used. Example (this uses [x]A instead of x->A or "lambda" x . A I can't even type a lambda). ? (x (x y)) => (x (x y)) ? ([x]x b) => b ? ([x]y b) => y ? ([x](x (x y)) (a b)) => ((a b) ((a b) y)) ? ([x][y](x y) n) => [y](n y) in that one, the bound variable (y) would be likely to have had its name chaged, so it could come out as [y2](n y2) or [v179](n v179) or whatever. ? (([x][y](x y) n) p) => (n p) ? ([x]( (x (a x)) [x](x (a x)) ) n) => ((n (a n)) [x](x (a x))) look at this special note http://rabbit.eng.miami.edu/class/een511/lamrenaming.pdf for a reminder about the rules that one could also have come out as => ((n (a n)) [v1709](v1709 (a v1709))) or some such. At the beginning, you will want to have your program be more interactive, telling you the result of every reduction, not just the final result, and waiting until you say "continue" or "stop" so you get a chance to see what's happening. When it seems to be working, you should allow definitions to be made. Clumsy primitive syntax is allowed to make it simpler. For example I might use the symbol * to indicate a definition: ? * a [x](y x) a defined to be [v12](y v12) ? * b (p q) b defined to be (p q) ? (a b) => (y (p q)) ? (b a) => ((p q) [v17](y v17)) Then the real test is possible: see if the arithmetic operations work.