Try writing a type inference engine. I did one over the last few days as the first big step in a game scripting language I'm working on - and at least in my case the implementation turned out to be only a bit convoluted; the main hurdles are in the details of coercions and casts. Once you have the engine running you can get lots of "bang" out of it in terms of helpful error messages and syntactical conveniences.
I represent the different types and coercions as graph nodes(casts are direct connections between types), and then cache all the possible paths for inference by walking the tree from each node with a depth-first search.
Once the graph is set up and the paths are assigned, then I can run tests to see if a coercion path is possible, whether additional coercion or casting steps are needed, and if there is an ambiguity in the input or output types at any point. Today I retrofitted my engine to include multiple arguments in coercions, so that many->one functions can be included in the graph.
A side effect of resolving ambiguities is that I have to include hinting for both which argument of the coercion is used for input, and for the output type, if multiple output types are possible.
I should describe the two goals of my language while I'm at it:
1. To allow the game engine to treat its entities and components as types, so that the scripts never have to deal with the difference between a "Monster" archetype and a "Collision" component attached to the monster - where the collision data is, and how it's accessed, are just part of the type system. Thus the syntax will let you say something like move(me(),vec2D(3,3)); without explicitly resolving me() into "the collision component of the entity of the calling script."
2. The language includes constructs for timing and tweening; events are atomic transactions with applicative/imperative abilities, but they hold a time value, and yield execution after processing "everything that happened" during a single update timeslice; the script can jump to different moments in time to loop a cycle of actions; and tweening operations like fades or bounce effects can be queued to run on every update with new parameters, so that there is no more timer bookkeeping going on.
I still have to nail down all the details of the runtime model, and then the syntax. But so far it's looking pretty good.