HOW TO RUN PROLOG
Principles of Programming Languages 198:314   Fall 2001

You will be running SICStus Prolog on the undergraduate SUN servers. The preferred way to run Prolog is from within emacs, as then your output is in an emacs window, which can be manipulated as text.

Use a two window (i.e., buffer) emacs environment, which encourages an interactive style of editing and running Prolog programs. The upper window is used primarily for editing of facts and rules. The lower window (which is running the shell) is used for executing programs; it keeps a running record of your execution. Thus, you can save the results of a Prolog session by saving this lower window using the usual emacs file saving commands (e.g., Control-x Control-w).

TO START:

The command emacs will get you into Gnu Emacs. Then, the following command sequence should be executed (where Control-a stands for depressing the control key while hitting the keyboard key a and Esc stands for hitting the escape key by itself). Note, these commands are all Gnu Emacs commands to setup your two windows for maximal ease of execution; the Prolog commands are explained in the section INSIDE PROLOG.
Control-x 2
creates two windows (Emacs buffers) on your screen, one above the other
Control-x o
puts the cursor in the lower buffer; this is a toggle instruction which can switch you from window to window and back again
Esc x run-prolog
this gets Prolog running in the lower window and sets up the upper window for editing Prolog programs. You will see the Prolog header appear on the top of the lower window followed by the Prolog prompt ?-

 

 

After you execute this command, you type into the emacs buffer exactly as you would at the system level. After you end the Prolog session by typing ?- halt., you can save your output buffer to a file.

INSIDE PROLOG:

You are now ready to start defining Prolog programs and running them. You can save your Prolog programs and run them again; the expected Prolog source file extension is .pl. (Unfortunately) all rules and facts with the same left-hand side predicate must be defined in the same file.

We expect you to run as follows:

  1. Create your clauses in the emacs window and save them to a file foo.pl.
  2.  While running Prolog within emacs, load this file into the interpreter: ?-[foo].
  3.  Then run some queries using the predicates you have defined, and test your clauses. You can make changes easily within the emacs window, save them to foo.pl, reload the file into Prolog and then test the changed version.
NOTE: although there is a way to new facts or rules in the Prolog window itself, you haven't been taught this; you should always go back to the file, edit it, and reload it. To leave Prolog exit emacs as usual (e.g., Control-x Control-c). You will be asked about saving any buffers you have opened during the emacs session.

Infinite loops in Prolog programs, usually caused by poorly written recursive rules (e.g., a base case entered *after* the recursive rule, or a leftmost recursive subgoal on the rhs of a rule), are easy to notice: if the interpreter produces no output to the screen for a while, your program is probably in an infinite loop. When running Prolog, Control-c Control-c (yes, it's two of them) interrupts execution and results in the Prolog prompt for help. If you reply to the prompt h, thus asking for help, these are some of the choices open to you:

t trace - debugger will be activated and will start creeping; this means a step-by-step trace of your execution is provided (see below).
d debug - debugger will be activated and will start leaping; this is a skipping trace that doesn't trace every statement.
a abort - causes a Prolog execution abort; this gets you a prompt for more queries to be entered.
e exit - causes an irreversible exit from Prolog.
h help - prints a longer version of this list
To restart execution after an exit, you will have to use the Esc x run-prolog sequence again.

DEBUGGING AND TRACING:

To trace a running Prolog program there are many options. You can trace the step-by-step execution of the program. You can trace the program, but skip some of the intermediate steps. You can watch just one predicate as the rules defining it are executed; this means execution proceeds as normal until that predicate is hit and then step-by-step tracing begins and continues as long as a rule for that predicate is executing. The command trace. starts step-by-step execution of subsequent queries. The trace command normally stops at every line; you must type carriage return to make it continue. Once you are in trace mode you can switch back to no trace mode by saying notrace. at the Prolog prompt.

spy(). -- causes a trace of the execution of the specified clause only. During execution, once that clause is reached, the trace is presented and several options are possible:

Return -- single step trace
l -- leap trace (allows you to skip over subgoals)
? -- help
g -- shows the ancestor list of current goals not yet satisfied

  The following program was run on remus and traced as shown below, to give you an idea of what the trace output means. The annotations which follow the % on the right, as well as the indentation were inserted after the run of the program. Note that Head [j->k] p(...) indicates that the j-th rule for predicate p is being tried currently, and then the k-th rule will be tried next. Head [j] p(...) means there are no more rules to try for p.

Program Used (in file mem.pl:)

\% mem(X,List) --X is member of list L
   mem(A,[A|B]).                  %rule 1 for mem: standard base case
   mem(A,[C|B]) :- mem(A,B),fail. %rule 2 for mem (useless- just to show trace)
   diff(X,Y):- \+(X=Y).           %mixed in definition of diff/2
   mem(A,[C|X]) :- diff(C,A), mem(A,X).  %rule 3 for mem.

Output Obtained in emacs:

| ?- trace.
[trace]
| ?- mem(a,[b,a]).
 (1) 0 Call: mem(a,[b,a]) ? 
 (1) 1 Head [1->2]: mem(a,[b,a]) ?  %try rule 1 (rule 2 is next)
 (1) 1 Head [2->3]: mem(a,[b,a]) ?  %try rule 2 (rule 3 is next)
   (2) 1 Call: mem(a,[a]) ?           
         (2) 2 Head [1->2]: mem(a,[a]) ?    %try rule 1 (rule 2 is next)
   (2) 1 Exit: mem(a,[a]) ?           %1. succeeded
   (2) 1 Redo: mem(a,[a]) ?           % fail kicked back
         (2) 2 Head [2->3]: mem(a,[a]) ?    %try rule 2 (rule 3 is next)
           (3) 2 Call: mem(a,[]) ?            
           (3) 3 Head [1->2]: mem(a,[]) ?     %try rule 1 (rule 2 is next)
           (3) 3 Head [2->3]: mem(a,[]) ?     %try rule 2 (rule 3 is next)
           (3) 3 Head [3]: mem(a,[]) ?        %try rule 3
           (3) 2 Fail: mem(a,[]) ?            %ran out of choices
         (2) 2 Head [3]: mem(a,[a]) ?     %try rule 3
          (4) 2 Call: diff(a,a) ? 
          (4) 3 Head [1]: diff(a,a) ? 
          (4) 2 Fail: diff(a,a) ? 
   (2) 1 Fail: mem(a,[a]) ?          %ran out of choices after redo
 (1) 1 Head [3]: mem(a,[b,a]) ?   %try rule 3
    (5) 1 Call: diff(b,a) ?      %first goal of rule %3
    (5) 2 Head [1]: diff(b,a) ? 
    (5) 1 Done: diff(b,a) ? 
    (6) 1 Call: mem(a,[a]) ?     %second rule of rule 3
        (6) 2 Head [1->2]: mem(a,[a]) ?    %quick recursion
        (6) 1 Exit: mem(a,[a]) ? 
 (1) 0 Exit: mem(a,[b,a]) ? 

Yes