Some examples and simplifications

I did some changes to make it more pleasant to write expressions. Also, turns out that the unify function we wrote works inside any monad, so `liftError` is not really needed.

For the engine to work correctly, the variables in a rule should be "freshened" before it's applied. This can be done by keeping a global, incremental counter, and adding a numeric suffix to the names of the variables before using the rule. It's a good opportunity to use monad transformers, combining non-determinism with state.