S9 LIB  (amb <expression> ...)  ==>  object
        (amb-collector)         ==>  procedure
        (amb-done? object)      ==>  boolean
        (amb-reset)             ==>  unspecific

        (load-from-library "amb.scm")

Another variation of McCarthy's AMB operator.

AMB takes a list of <expressions>, immediately evaluates the first one
and returns its value. When no <expression>s are passed to AMB (or it
runs out of <expressions>), it checks whether there is another AMB further
up in the program structure. If it is, it returns control to that instance
of AMB, thereby initiating backtracking. When backtracking to an AMB that
AMB evaluates the next <expression> from its argument list, and so on.

When an AMB runs out of options and there is no AMB to return control
to, it returns a special object that can be detected with AMB-DONE?.

AMB-COLLECT generates a procedure of the form

      (lambda (p . v*) ...)

where P is a predicate and V* is a list of values. When called, the
procedure will apply P to V* and if the predicate is satisfied, it will
store the values internally and initiate backtracking by calling (amb).
When one of the values V* satisfies AMB-DONE?, the procedure will
return the list stored internally. At this point, the list contains
the union of all combinations of AMB values that satisfy P.

AMB-RESET clears the AMB tree. It serves as a CUT operator and an
initializing procedure are the same time. After calling AMB-RESET
(amb) will always fail. Any program that uses AMB should first call
AMB-RESET.

(begin (amb-reset)
       (let ((collect (amb-collector)))
         (let ((x (amb 4 1 7)))
           (let ((y (amb 6 8 2)))
             (let ((z (amb 5 3 9)))
               (collect > x y z))))))  ==>  ((7 6 3) (7 6 5))
