The above is an implementation of unification in Common Lisp. It won't, by itself, tell you how unification works, or the resulting implications. It's a very mildly modified version of the unifier that Norvig built in PAIP. What a lot of people don't grasp intuitively|1| is that unifiers don't return expressions, they return environments.

This particular implementation represents environments as association list, but that's not a requirement. An environment is a key/value structure that tells you what variables are bound to which values. The three possible outputs of unify are:

Failure, which is the unsuccessful empty environment. Here's an example:

FACT-BASE> (unify '(?a :test 1) '(:blah ?b 2))
#:FAIL973
FACT-BASE>

The problem there is that 1 and 2 are different constant values, so these two terms can't be unifyied. This is fundamentally different from

Success, which is the successful empty environment. You get this by successfully unifying terms with no variables. For example,

FACT-BASE> (unify '(:blah :test 2) '(:blah :test 2))
NIL
FACT-BASE>

This particular implementation of unify uses the empty list (NIL) as the empty success. And finally, unify might return

An Environment, which is a set of bindings under which the given unification is true. Once again,

If unify tries to work on these same terms, but ?a is already bound to :foo, it can do nothing but fail. Yes, you could unbind a particular variable, but that's skipping ahead a bit. Backtracking is dealt with at a different level than straight-up unification. In fact...

This'll get funny eventually, I swear. In all seriousness, understanding this implementation of for-all is entirely optional to understanding how you use unify to query a fact-base. Here's a simple query:

In fact, this is about the upper bound of complexity you're likely to run into in a single query. You can read the full statement more or less the same way as above, but the "this query" part is much more complicated. In this case, rather than just going through each fact in base and unifying it, for-all needs to run a deeper query. The top-level and there means that these sub-clauses are dependent on each other. So what it does is go through base looking for a fact that unifyies with (?id :line-segment nil). If it finds such a fact, lets say it looks like (27 :line-segment nil), it then tries to satisfy the next and clause under the resulting set of bindings. That is, it tries to find another fact in base that satisfies

(unify fact (?id :start ?start) '((?id . 27)))

If that works, it keeps going. Either until it gets to the end of its clauses, in which case it returns the presumably fairly large environment which satisfies all of them, or until it gets to a sub-clause that fails. If that first sub-clause fails, for-all is out of answers in the given base, and is therefore done. If it were to fail on some other clause, it backtracks. That is, if (unify fact (?id :start ?start) '((?id . 27))) fails above, for-all will go back to the first goal and start searching where it left off until it finds another satisfying fact, then try to move up the tower again.