This is done by requiring applications to be at least 2 terms,
and making grouping a syntactic feature instead of a feature of applications.
I also made the code a bit more clear by handling whitespace a bit more cleanly;
now, each parser is responsible for its own trailing whitespace,
and whitespace handling is pushed down to the token level
to avoid cluttering high-level definitions with whitespace stuff.
This all also had the effect of improving error messages,
in part due to me labelling many of the parsers.
* The expression printer now knows how to use `let`, multi-argument lambdas and applications, and block arguments when appropriate.
* There is a separate type, AbstractSyntax, which separates parsing/printing logic from removing/reintroducing the more advanced syntax described above.
* Expression is now its own module because its 'show' depends on AbstractSyntax,
and I don't want the ast2expr/expr2ast stuff to be in the same module as the real lambda calculus stuff.
* Allows for multiple representations
* Evaluation strategies
* Type systems.
* No longer just the untyped lambda calculus.
* No longer "just an experiment".