Figure 3: A Bottom-Up Prolog Interpreter
  iterate :-                            
      operator, fail.                      
  iterate :-                              
      retract(flag),                     
      iterate
  iterate.                              
                                        
  record(F) :- cond_assert(F).
                      
  raise_flag :-                         
      ( flag ->  true 
      ;   assert(flag)
      ).               
  
  cond_assert(F) :-   
      \+ (numbervars(F,0,_), fact(F)), 
      assert(fact(F)), raise_flag.
(a) the control               
  operator :-
      my_clause(H,B),
      prove(B),
      record(H).

  prove([B|Bs]) :-
      fact(B),
      prove(Bs).
  prove([unify(A,B)|Bs]) :-
      unify(A,B),
      prove(Bs).
  prove([]).
(b) the logic       


    go(File) :-                             showfacts :-
        load_file(File),                        fact(F),
        iterate,                                numbervars(F,0,_),
        showfacts.                              print(F), nl,
                                                fail ; true.

(c) using the interpreter

The interpreter in Figure 3 is divided conceptually into three components. On the left (a) is the ``control'' component which triggers iteration of an operator until no new facts are derived. When a new fact gets inserted into the Prolog database, a flag is raised. Iteration stops when retract(flag) fails in the second clause for iterate, that is, when no new facts were asserted in the previous iteration. On the right (b), the predicate operator provides the ``logic'' and the inner loop of the algorithm which for each my_clause(Head,Body) in P proves the Body using facts derived so far and calls the predicate record which adds the Head to the set of facts derived so far, provided it is a new fact. In this version of the interpreter, a fact F is considered new if it is not subsumed by a fact which is already recorded (and hence implements the c-semantics). The subsumes check for F is implemented by application of the built-in predicate numbervars(F,0,_) which instantiates the variables in F (with fresh constant symbols) and then calling fact(F). This should fail if F is to be considered new (and hence does not affect the variables in the recorded fact). The distinction between record and cond_assert is unnecessary at this point, but it will prove useful when we consider variations of the interpreter. The second clause in the definition of prove is for the case when unification is made explicit and should be considered as a built-in predicate by the interpreter.

Bottom-up evaluation is initiated by the query ?- iterate which leaves the result of the evaluation in the Prolog database. In (c) the predicate go facilitates the use of the interpreter. This predicate loads the program to be interpreted, initiates iteration and finally prints the derived facts on the screen. Of course this interpreter will only work in case the semantics of the program is finite.