The expression containing the case expression. If
the type to inspect is t and the type of the Exp
returned by the case handling function is r, the
Exp returned by thcase is of type t -> r.

Case expression generation. This is the core function of the
Template Your Boilerplate library.

This function is similar to thcase', except that since most users
will note care about the distinction between types and primitive
types, this function smooths over the differences by treating primitive
types as types with nullary constructors.

Case handling function. If the Type being inspected is
a primitive type, argument is Left var where var is a
variable bound to the case discriminant. Otherwise,
argument is Right (ctor, args) where ctor is the
constructor name and args is a list of the argument's
types and the variable bound to the argument.

The result of applying the
function to the initial argument.
The |Exp| is the result, but
expects the [Dec] to be in
scope.

Memoizes a code generation function. Most users will want to use
memoizeExp instead as it provides a simplified interface, but all
the notes about this function also apply to memoizeExp.

We memoize a function returning an Exp by creating a Dec with a
body that is the Exp returned by that function. The return value
of the function is replaced with a VarE that refers to the Dec.
This allows functions like everywhere to avoid infinite
recursions when they traverse recursive types like lists.

The memoization functions come in two flavors: memoizeDec and
memoizeExp. With memoizeDec it is the responsibility of the
caller to place the Dec in an appropriate place. The
memoizeExp function automatically handles the Dec by wrapping
them in a local LetE form.

Every memoized function is passed a memoized version of itself.
This is the function that should be used in recursive calls.
Failing to do so will prevent those calls from being memoized.

If the function being memoized needs to accept multiple arguments,
then they must be packed into a tuple and passed as a single argument.

Effects in the m monad are only performed the first time the
memoized function is called with a particular argument. Subsequent
times the monad is simply the result of a return. Thus while it
is tempting to store extra return values in the monad, this should
be avoided due to the high likelihood of unexpected behavior.

Implementation Notes:

Note that m should not store a copy of the function, otherwise
a memory leak is introduced. It wouldn't even make sense to do
it anyway since the results refer to expressions that might not
be in scope.

The memoized function stores a reference to the memoization
table, Thus if a reference to the memoized function gets tucked
inside m, then a memory leak can be introduced. We could
eliminate this leak by clearing and invalidating the table when
memoizeDec returns. To fully do this properly the table would
have to be invalidated in such a way that the memoized version of
the function would not continue to try populating the table if
the user called it after memoizeDec return.

Conceptually we should use a State monad instead of an IORef but
we choose IORef since we can embed IO operations in a Quasi
without imposing extra restrictions on m.

Other designs are possible. This design was choosen for its
simplicity of use. The choice of memoization interface is
largely orthogonal to the rest of this library.

Type synonyms and kind annotations may lead to duplicate versions
of the code (e.g. versions for both String and [Char])
Usually this isn't a problem, but if it is, then the type
synonyms should be expanded before each call to the memoized
function.

GADTs and data/type families haven't been considered in this
code. It is unknown whether they work.

Note that polymorphically recursive types (e.g. data F a = N a | F (F
(Int, a))) have an infinite number of types in them and thus despite
memoization this function will not terminate on those types.

The result of applying the function to the
initial argument. The |Exp| is the result, but
expects the [Dec] to be in scope.

Simultaneously memoizes two code generation functions. All of
the notes about memoizeDec also apply to this function. Most
users will want to use memoizeExp2 instead of this function as it
provides a simplified interface.

The transformation. The first argument is the memoized
recursion. If Nothing is returned, then the standard,
automatic recursion is done. If Just is returned, then no
automatic recursion is done and the resulting Exp is used at
that type. In that case, if further recursion is desired, then
the expression should include a call to the memoized recursion.
If the Type is t, then the returned Exp must be of type t
-> t.

We use Maybe instead of MonadPlus to avoid the user having to
play games with runMaybeT and so forth.

The monadic transformation. The first argument is the memoized
recursion. If Nothing is returned, then the standard,
automatic recursion is done. If Just is returned, then no
automatic recursion is done and the resulting Exp is used at
that type. In that case, if further recursion is desired, then
the expression should include a call to the memoized recursion.
If the Type is t, then the returned Exp must be of type t
-> m t.

We use Maybe instead of MonadPlus to avoid the user having to
play games with runMaybeT and so forth.