home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / TP_ALGO.ZIP / TP_ALGO.TXT
Encoding:
Text File  |  1986-05-27  |  31.6 KB  |  724 lines

  1.  
  2.  
  3.  
  4.  
  5.                    Expressing Procedural Algorithms in Prolog
  6.  
  7.                               Michael A. Covington
  8.  
  9.                              Research Report 01-0012
  10.                       Advanced Computational Methods Center
  11.                               University of Georgia
  12.                               Athens, Georgia 30602
  13.  
  14.                               May 26, 1986  4:25 pm
  15.  
  16.           --------------------------------------------------------------
  17.           This work was supported by PACER Grant 85PCR18 from Control
  18.           Data Corporation and by Grant Number INS-85-02477 from the
  19.           National Science Foundation. The opinions expressed here are
  20.           solely those of the author. The assistance of Donald Nute and
  21.           Andre Vellino is gratefully acknowledged. Printed copies of
  22.           this and other research reports are available free on request.
  23.           --------------------------------------------------------------
  24.  
  25.         With the increasing popularity of Prolog as an application
  26.         programming language, it is often necessary to develop Prolog
  27.         equivalents for algorithms that were originally expressed in 
  28.         procedure-oriented languages. This paper presents a number of
  29.         strategies for doing so. I assume that the reader is already
  30.         familiar with the basic mechanisms of Prolog -- unification
  31.         (matching), backtracking, and the like.
  32.  
  33.         Unless otherwise noted, the examples given here work both in full
  34.         "Edinburgh" or "DEC-10" Prolog (Clocksin and Mellish 1984) and in
  35.         Turbo Prolog (1986), which is a subset of the full language. The
  36.         examples are written in Turbo Prolog syntax, but with declarations
  37.         omitted for brevity. Full Prolog is used -- and noted as such --
  38.         when its features are needed.
  39.  
  40.         The procedural interpretation of logic
  41.  
  42.         Prolog is often described as a non-procedural language. In
  43.         reality, it is a semi-procedural language -- a compromise between
  44.         procedural and non-procedural programming, giving some of the
  45.         advantages of each. In a truly non-procedural language, the
  46.         programmer would provide only a logically rigorous set of
  47.         conditions that the program must fulfill; the computer would then
  48.         automatically generate an algorithm from them. Such things as the
  49.         order in which the conditions were written would have no effect.
  50.  
  51.         In the interest of efficiency, Prolog contains some procedural
  52.         elements. The Prolog programmer specifies not only the rules of
  53.         inference to be used in solving a problem, but also the order in
  54.         which they are to be tried. Crucially, the programmer can even
  55.         specify that some potential paths to a solution should not be
  56.         tried at all. This makes it possible to perform efficiently many
  57.  
  58.  
  59.  
  60.                                                                       2
  61.  
  62.         computations that would be severely inefficient, or even
  63.         impossible, in pure Prolog.
  64.  
  65.         The key principle of Prolog is the procedural interpretation of
  66.         logic. Consider the following Prolog rule set:
  67.  
  68.         [1]         in_north_america(X) :- in_usa(X).
  69.                     in_usa(X) :- in_georgia(X).
  70.                     in_georgia(atlanta).
  71.  
  72.         This can be interpreted as a set of facts ([2] below) or as a set
  73.         of procedure definitions ([3] below).
  74.  
  75.         [2]         X is in North America if X is in the USA.
  76.                     X is in the USA if X is in Georgia.
  77.                     Atlanta is in Georgia.
  78.  
  79.         [3]         To prove that X is in North America,
  80.                          prove that X is in the USA.
  81.                     To prove that X is in the USA,
  82.                          prove that X is in Georgia.
  83.                     To prove that Atlanta is in Georgia,
  84.                          do nothing.
  85.  
  86.         The unfamiliar task of drawing inferences from data is thereby
  87.         reduced to the very familiar task of calling procedures.
  88.  
  89.         In what follows I will unashamedly refer to Prolog predicate
  90.         definitions as procedures.
  91.  
  92.         Conditional execution
  93.  
  94.         One of the most important differences between Prolog and other
  95.         programming languages is that, in general, Prolog procedures have
  96.         multiple definitions (clauses), each applying under different
  97.         conditions. In Prolog, conditional execution is expressed, not
  98.         with if or case statements, but with these alternative definitions
  99.         of procedures.
  100.  
  101.         Consider for example how we might translate into Prolog the
  102.         following Pascal procedure:
  103.  
  104.         [4]         procedure writename(X:integer);
  105.                     begin
  106.                       case X of
  107.                         1: write('One');
  108.                         2: write('Two');
  109.                         3: write('Three')
  110.                       end
  111.                     end;
  112.  
  113.         This is done by giving writename three definitions:
  114.  
  115.  
  116.  
  117.                                                                       3
  118.  
  119.  
  120.         [5]         writename(1) :- write("One").
  121.                     writename(2) :- write("Two").
  122.                     writename(3) :- write("Three").
  123.  
  124.         Each definition matches in exactly one of the three cases. A
  125.         common mistake is to write the clauses as follows:
  126.  
  127.         [6]         /* bad style */
  128.  
  129.                     writename(X) :- X=1, write("One").
  130.                     writename(X) :- X=2, write("Two").
  131.                     writename(X) :- X=3, write("Three").
  132.  
  133.         This gives correct results but is needlessly inefficient. It is a
  134.         waste of time to go into an inapplicable clause, perform a test
  135.         that fails, backtrack out, and try another clause, when the use of
  136.         the inapplicable clause could have been avoided in the first
  137.         place.
  138.  
  139.         A key to effective programming in Prolog is making each logical
  140.         unit of the program into a separate procedure. Each if or case
  141.         statement should, in general, become a procedure call. For
  142.         example, the hypothetical Pascal procedure:
  143.  
  144.         [7]         procedure a(X:integer);
  145.                     begin
  146.                       b;
  147.                       if X=0 then c else d;
  148.                       e
  149.                     end;
  150.  
  151.         should go into Prolog as follows:
  152.  
  153.         [8]         a(X) :- b,
  154.                             c_or_d(X),
  155.                             e.
  156.  
  157.                     c_or_d(0) :- c.
  158.                     c_or_d(X) :- X<>0, d.
  159.  
  160.         This imposes a disciplined organization on the program that is
  161.         even more rigorous than the structured ("go-to-less") programming
  162.         that serves as the basis of Pascal, Ada, and C.
  163.  
  164.         Guarded command sets
  165.  
  166.         As Kluzniak and Szpakowicz (1985) have pointed out, Dijkstra's
  167.         "guard" concept (Dijkstra 1975) is easily expressed in Prolog. A
  168.         guarded command set is a structure of the form
  169.  
  170.  
  171.  
  172.  
  173.                                                                       4
  174.  
  175.         [9]         if
  176.                       C1 -> A1
  177.                       C2 -> A2
  178.                       C3 -> A3
  179.                     fi
  180.  
  181.         where C1, C2, and C3 are conditions and A1, A2, and A3 are the
  182.         corresponding actions. During program execution, all the
  183.         conditions are evaluated. If all of the conditions are false, the
  184.         program terminates. Otherwise, one of the actions corresponding to
  185.         a true condition is selected for execution.
  186.  
  187.         If exactly one condition is true, the guarded command set is
  188.         equivalent to an if-then or case statement. In fact, the Prolog
  189.         procedure "c_or_d" in [8] can be expressed in more Dijkstra-like
  190.         (though less efficient) form as:
  191.  
  192.         [10]        c_or_d(X) :- /* condition */ X=0,  /* action */ c.
  193.                     c_or_d(X) :- /* condition */ X<>0, /* action */ d.
  194.  
  195.         Guarded command sets were developed as part of a system for
  196.         deriving algorithms from formal specifications of the problems
  197.         they must solve. In Dijkstra's system, if more than one condition
  198.         is true, no assumptions are made about which action will be taken.
  199.         In Prolog, all possible actions will be taken on successive
  200.         backtracking passes, in the order in which they are given in the
  201.         program.
  202.  
  203.         The "cut" operator
  204.  
  205.         Let's consider another version of "writename" ([4] above) that
  206.         includes a "catch-all" clause to deal with numbers whose names are
  207.         not given. In many extended forms of Pascal, this can be expressed
  208.         as:
  209.  
  210.         [11]        procedure writename(X:integer);
  211.                     begin
  212.                       case X of
  213.                         1: write('One');
  214.                         2: write('Two');
  215.                         3: write('Three')
  216.                       else
  217.                         write('Out of range')
  218.                       end
  219.                     end;
  220.  
  221.         One way to express this in Prolog is the following:
  222.  
  223.  
  224.  
  225.  
  226.                                                                       5
  227.  
  228.         [12]        writename(1) :- write("One").
  229.                     writename(2) :- write("Two").
  230.                     writename(3) :- write("Three").
  231.                     writename(X) :- X<1, write("Out of range").
  232.                     writename(X) :- X>3, write("Out of range").
  233.  
  234.         This gives correct results but lacks conciseness. In order to make
  235.         sure that only one clause is applicable to each number, we have
  236.         had to add two more clauses. What we would like to say is that the
  237.         program should print "Out of range" for any number that has not
  238.         matched any of the first three clauses. We could try to express
  239.         this as follows, with some lack of success:
  240.  
  241.         [13]        /* incorrect */
  242.                     writename(1) :- write("One").
  243.                     writename(2) :- write("Two").
  244.                     writename(3) :- write("Three").
  245.                     writename(_) :- write("Out of range").
  246.  
  247.         (Recall that the anonymous variable, written _, matches anything.)
  248.         The problem here is that the goal "writename(1)", for example,
  249.         matches both the first clause and the last clause. If a subsequent
  250.         goal fails and causes backtracking through this one, the goal
  251.         "writename(1)" will have two solutions, one that prints "One" and
  252.         one that prints "Out of range."
  253.  
  254.         We want "writename" to be deterministic, that is, to give exactly
  255.         one solution for any given set of parameters, and not give
  256.         alternative solutions upon backtracking. We would therefore like
  257.         to specify somehow that if any of the first three clauses
  258.         succeeds, the computer should not try the last clause. This can be
  259.         done with the "cut" operator (written as an exclamation mark). 
  260.  
  261.         The cut operator commits the computer to take a particular
  262.         solution (or potential solution) without trying alternatives.
  263.         Suppose for example that we have the following rule set:
  264.  
  265.         [14]        b :- c, d, !, e, f.
  266.                     b :- g, h.
  267.  
  268.         and that the current goal is "b". If we take the first clause and
  269.         execute the cut, then it becomes impossible to look for
  270.         alternative solutions to "c" and "d" (the goals that precede the
  271.         cut in the same clause) or to "b" (the goal that invoked the
  272.         clause containing the cut). It remains possible, of course, to
  273.         backtrack all the way past "b" and look for alternatives to the
  274.         clause that caused "b" to be invoked.
  275.  
  276.         What we need to do in [13] is to put a cut in each of the first
  277.         three clauses. This changes their meaning slightly, so that the
  278.         first clause (for example) says, "If the parameter is 1, then
  279.         write 'One' and do not try any other clauses."
  280.  
  281.  
  282.  
  283.                                                                       6
  284.  
  285.  
  286.         [15]        writename(1) :- !, write("One").
  287.                     writename(2) :- !, write("Two").
  288.                     writename(3) :- !, write("Three").
  289.                     writename(_) :- write("Out of range").
  290.  
  291.         Since "write" is deterministic, it does not matter whether the cut
  292.         is written before or after the call to "write". However, programs
  293.         are usually more readable if cuts are made as early as possible.
  294.  
  295.         Making procedure calls always succeed or always fail
  296.  
  297.         In order to control the flow of program execution, it is often
  298.         necessary to guarantee that a goal will always succeed regardless
  299.         of the results of the computation that it performs. Occasionally,
  300.         it is necessary to guarantee that a goal will always fail.
  301.  
  302.         An easy way to make any procedure succeed is to add an additional
  303.         clause to it that succeeds with any parameters, and is tried last,
  304.         thus:
  305.  
  306.         [16]        f(X,Y) :- X < Y, !, write("X less than Y").
  307.                     f(_,_).
  308.  
  309.         A call to "f" succeeds with any parameters; it may or may not
  310.         print its message, but it will certainly not return failure and
  311.         hence will not cause backtracking in the procedure that invoked
  312.         it. Moreover, because of the cut, "f" is deterministic. The cut
  313.         prevents the second clause from being used to generate a second
  314.         solution with parameters that have already succeeded with the
  315.         first clause.
  316.  
  317.         Similarly, a procedure can be guaranteed to fail by adding cut and
  318.         fail at the end of each of its definitions, thus:
  319.  
  320.         [17]        g(X,Y) :- X<Y, write("X less than Y"), !, fail.
  321.                     g(X,Y) :- Y<X, write("Y less than X"), !, fail.
  322.  
  323.         Any call to "g" ultimately returns failure for either of two
  324.         reasons: either it doesn't match any of the clauses, or it matches
  325.         one of the clauses and ends with cut and fail. The cut is written
  326.         next to last so that it won't be executed unless all the other
  327.         steps of the clause have succeeded; as a result, it is still
  328.         possible to backtrack from one clause of "g" to another.
  329.  
  330.         In full Prolog, but not in Turbo Prolog, we can define procedures
  331.         "make_succeed" and "make_fail" that take a goal as a parameter,
  332.         thus:
  333.  
  334.  
  335.  
  336.  
  337.                                                                       7
  338.  
  339.         [18]        make_succeed(Goal) :- call(Goal), !.
  340.                     make_succeed(_).
  341.  
  342.                     make_fail(Goal) :- call(Goal), !, fail.
  343.  
  344.         In some implementations, "call(Goal)" is written simply as "Goal".
  345.  
  346.         Likewise, in full Prolog but not in Turbo Prolog we can define the
  347.         procedure "once" which allows a goal to succeed exactly once, thus
  348.         making any goal deterministic:
  349.  
  350.         [19]        once(Goal) :- call(Goal), !.
  351.  
  352.         This procedure backtracks as much as necessary to get one
  353.         successful solution to "Goal", then stops. Thus, no matter how
  354.         many possible solutions there are to "f(p)", the goal "once(f(p))"
  355.         will return only the first solution. If "f(p)" has no solutions,
  356.         "once(f(p))" fails.
  357.  
  358.         Repetition through backtracking
  359.  
  360.         Prolog offers two ways to perform computations repetitively:
  361.         backtracking and recursion. Of the two, recursion is by far the
  362.         more versatile. However, there are some interesting uses for
  363.         backtracking, among them the construction of "repeat-fail" loops.
  364.         In Prolog implementations that lack tail recursion elimination
  365.         (see below), "repeat-fail" looping is the only kind of iteration
  366.         that can be performed ad infinitum without causing a stack
  367.         overflow.
  368.  
  369.         The predicate "repeat" is built into some Prolog implementations.
  370.         In most others, it can be defined as follows:
  371.  
  372.         [20]             repeat.
  373.                          repeat :- repeat.
  374.  
  375.         (The built-in version of "repeat" should be used if available,
  376.         since there are a few implementations in which the definition in
  377.         [20] does not prevent stack overflow.)
  378.  
  379.         "Repeat" always succeeds and has an infinite number of solutions.
  380.         Thus any procedure call bracketed between "repeat" and "fail" will
  381.         be tried over and over again, even if it only generates one
  382.         solution. For instance, the following goal displays an infinite
  383.         number of asterisks:
  384.  
  385.         [21]             repeat, write("*"), fail.
  386.  
  387.         The following Turbo Prolog procedure turns the computer into a
  388.         typewriter, accepting characters from the keyboard and displaying
  389.         them ad infinitum, until the user hits "Break" to abort the
  390.         program:
  391.  
  392.  
  393.  
  394.                                                                       8
  395.  
  396.  
  397.         [22]             typewriter :- repeat,
  398.                                        readchar(C),
  399.                                        write(C),
  400.                                        fail.
  401.  
  402.         The loop can be made to terminate by allowing it to succeed
  403.         eventually, so that backtracking stops. The following version of
  404.         "typewriter" stops when the user types a carriage return (ASCII
  405.         code 13):
  406.  
  407.         [23]             typewriter :- repeat,
  408.                                        readchar(C),
  409.                                        write(C),
  410.                                        C = '\13'.
  411.  
  412.         If C is equal to code 13, execution terminates; otherwise,
  413.         execution backtracks to "repeat" and proceeds forward again
  414.         through "readchar(C)" and "write(C)". 
  415.  
  416.         The looping in [23] can be restarted by the failure of a
  417.         subsequent goal (as in the compound goal "typewriter,fail"). To
  418.         prevent the loop from restarting unexpectedly, we need to add a
  419.         cut as follows:
  420.  
  421.         [24]             typewriter :- repeat,
  422.                                        readchar(C),
  423.                                        write(C),
  424.                                        C = '\13',
  425.                                        !.
  426.  
  427.         In effect, this forbids looking for alternative solutions to
  428.         "typewriter."
  429.  
  430.         There is a crucial difference between "repeat-fail" loops in
  431.         Prolog and repeat-until loops in Pascal. In Pascal, iteration is
  432.         always accomplished by executing all the statements in the loop,
  433.         then jumping from the end back to the beginning. In Prolog,
  434.         backtracking may cause control to jump backward from any goal to
  435.         any earlier goal that has alternative solutions. (The limiting
  436.         case is "repeat", which always has alternative solutions.)
  437.         Moreover, if any goal in a Prolog loop fails, subsequent goals
  438.         will not be attempted.
  439.  
  440.         A serious limitation of "repeat-fail" loops is that there is no
  441.         convenient way to pass information from one iteration to the next.
  442.         Prolog variables lose their values upon backtracking. Thus, there
  443.         is no easy way to make a "repeat-fail" loop accumulate a count or
  444.         total. (Information can be preserved by storing it in the
  445.         knowledge base, using "assert" and "retract", but this is usually
  446.         a slow process.) With recursion, information can be transmitted
  447.  
  448.  
  449.  
  450.                                                                       9
  451.  
  452.         from one pass to the next through the parameter list. This is the
  453.         main reason for preferring recursion as a looping mechanism.
  454.  
  455.         Recursion
  456.  
  457.         Most programmers are familiar with recursion as a means of
  458.         implementing some very specialized, task-within-a-task algorithms
  459.         such as tree searching and Quicksort. Indeed, Prolog lends itself
  460.         well to expressing recursive algorithms developed in Lisp. What is
  461.         not generally appreciated is that any iterative algorithm can be
  462.         expressed recursively.
  463.  
  464.         Here is the classic recursive algorithm for computing factorials,
  465.         expressed in Pascal and in Turbo Prolog. (Change "=" to "is" to
  466.         get standard Prolog.)
  467.  
  468.         [25]        function factorial(N:integer):integer;
  469.                     begin
  470.                       if N=0 then
  471.                         factorial:=1
  472.                       else
  473.                         factorial:=N*factorial(N-1);
  474.                     end;
  475.  
  476.         [26]        factorial(0,1).
  477.  
  478.                     factorial(N,FactN) :- N > 0,
  479.                                           M = N-1,
  480.                                           factorial(M,FactM),
  481.                                           FactN = N*FactM.
  482.  
  483.         This is straightforward; the procedure "factorial" calls itself to
  484.         compute the factorial of the next smaller integer, then uses the
  485.         result to compute the factorial of the integer in question. 
  486.  
  487.         Now consider an iterative algorithm to do the same thing:
  488.  
  489.         [27]        function factorial(N:integer):integer;
  490.                     var I,J:integer;
  491.                     begin
  492.                       I:=0;           /* Initialize */
  493.                       J:=1;
  494.                       while I<N do
  495.                         begin         /* Loop */
  496.                           I:=I+1;
  497.                           J:=J*I
  498.                         end;
  499.                       factorial:=J        /* Return result */
  500.                     end;
  501.  
  502.         In Pascal, this procedure does not call itself. Its Prolog
  503.  
  504.  
  505.  
  506.                                                                      10
  507.  
  508.         counterpart is a procedure that calls itself as its very last step
  509.         -- a procedure that is said to be tail recursive:
  510.  
  511.         [28]        factorial(N,FactN) :- fact_iter(N,FactN,0,1).
  512.  
  513.                     fact_iter(N,FactN,N,FactN).
  514.  
  515.                     fact_iter(N,FactN,I,J) :-
  516.                                      I < N,
  517.                                      NewI = I+1,
  518.                                      NewJ = J*NewI,
  519.                                      fact_iter(N,FactN,NewI,NewJ).
  520.  
  521.         Here the third and fourth parameters of "fact_iter" are state
  522.         variables that pass values from one iteration to the next. State
  523.         variables in Prolog correspond to variables that change their
  524.         values repeatedly in Pascal.
  525.  
  526.         Let's start by examining the recursive clause of "fact_iter". This
  527.         clause checks that I is still less than N, computes new values for
  528.         I and J, and finally calls itself with the new parameters. 
  529.  
  530.         The recursive call is the very last step in this clause, and in
  531.         addition, this whole clause is placed last so that, when it calls
  532.         itself, there will be no untried alternatives to be saved on the
  533.         stack. This ensures that the stack will not grow during the
  534.         iteration. (We will return to this point below.)
  535.  
  536.         Because Prolog variables cannot change their values, the
  537.         additional variables NewI and NewJ have to be introduced. In
  538.         Prolog (as in arithmetic, but not in most programming languages),
  539.         the statement
  540.  
  541.                          X = X+1
  542.  
  543.         is always false. So NewI and NewJ contain the values that will
  544.         replace I and J in the next iteration.
  545.  
  546.         The first clause of "fact_iter" serves to end the iteration when
  547.         the state variables reach their final values. A more Pascal-like
  548.         but less efficient way of writing this clause would be:
  549.  
  550.         [29]             fact(N,FactN,I,J) :- I = N, FactN = J.
  551.  
  552.         That is, if I is equal to N, then FactN (so far uninstantiated)
  553.         should be given the value of J. By writing this same clause more
  554.         concisely in [28], we make Prolog's unification mechanism do work
  555.         that would require explicit computational steps in other
  556.         languages.
  557.  
  558.         Most iterative algorithms can be expressed in Prolog by following
  559.         this pattern shown here. First transform other types of loops
  560.  
  561.  
  562.  
  563.                                                                      11
  564.  
  565.         (e.g., for and repeat-until) into Pascal while loops. Then break
  566.         the computation into three stages: the initialization, the loop
  567.         itself, and any subsequent computation needed to return a result.
  568.  
  569.         Express the loop as a tail recursive clause (like the second
  570.         clause of "fact_iter") with the while-condition at the beginning.
  571.         Computations to be performed after the loop terminates are placed
  572.         into another, non-recursive, clause of the same procedure, which
  573.         is set up so that it executes only after the loop is finished.
  574.  
  575.         Finally, hide the whole thing behind a "front-end" procedure
  576.         ("factorial" in this example) which is what the rest of the
  577.         program actually calls. The front-end procedure passes its
  578.         parameters into the tail recursive procedure along with initial
  579.         values of the state variables. The art of expressing iteration
  580.         through tail recursion is dealt with extensively, in Lisp, in the
  581.         first chapter of Abelson and Sussman (1985).
  582.  
  583.         Why tail recursion is special
  584.  
  585.         Whenever one Prolog procedure calls another, two things are saved
  586.         on a pushdown stack: (1) a record of what remains to be done after
  587.         return (the continuation of the calling procedure), and (2) a
  588.         record of what alternative solutions remain to be tried (the
  589.         alternative set). Normally, the continuation and the alternative
  590.         set are represented by pointers into already existing data
  591.         structures, so that it does not take any more space to represent a
  592.         large set than a small one.
  593.  
  594.         Since every procedure call places information onto the stack, it
  595.         would seem that recursion would lead inevitably to stack overflow.
  596.         However, most Prolog implementations (including Turbo Prolog)
  597.         recognize a special case: if the continuation and the alternative
  598.         list are both empty, nothing need be placed on the stack. In this
  599.         case, instead of calling itself, such a procedure can simply place
  600.         new values into its parameters and jump back to the beginning of
  601.         itself. In effect, this transforms recursion into iteration. 
  602.  
  603.         A procedure that calls itself with an empty continuation and empty
  604.         alternative list is described as tail recursive; the process of
  605.         executing such a call without adding items to the stack is called
  606.         tail recursion elimination. (The elimination of tail recursion
  607.         does not mean that it should be banished from the program; on the
  608.         contrary, it should be used liberally because the implementation
  609.         transforms it into an efficient iterative process.)
  610.  
  611.         A quick way to verify that a particular Prolog implementation
  612.         performs tail recursion elimination is to try the following
  613.         predicate:
  614.  
  615.  
  616.  
  617.  
  618.                                                                      12
  619.  
  620.         [30]             test(N) :- write(N), 
  621.                                     nl,
  622.                                     M = N+1, 
  623.                                     test(M).
  624.  
  625.         (Again, this is Turbo Prolog syntax; change "=" to "is" to get
  626.         standard Prolog.) Start with the goal "test(1)" and see how long
  627.         execution continues. If the program runs for more than 10,000
  628.         iterations, it is a safe bet that tail recursion elimination is
  629.         taking place.
  630.  
  631.         Controlling the growth of the stack
  632.  
  633.         It is easy to recognize a recursive call that has an empty
  634.         continuation: the recursive call is the very last subgoal in the
  635.         clause that contains it. Determining whether the alternative set
  636.         is also empty takes somewhat more thought.
  637.  
  638.         One way to get an empty alternative set is to put the recursive
  639.         call in the last clause of a predicate, as in the iterative
  640.         factorial program ([28], repeated here for convenience):
  641.  
  642.         [31]        factorial(N,FactN) :- fact_iter(N,FactN,0,1).
  643.  
  644.                     fact_iter(N,FactN,N,FactN).
  645.  
  646.                     fact_iter(N,FactN,I,J) :-
  647.                                      I < N,
  648.                                      NewI = I+1,
  649.                                      NewJ = J*NewI,
  650.                                      fact_iter(N,FactN,NewI,NewJ).
  651.  
  652.         The recursive call only takes place when all other alternatives
  653.         have been exhausted. 
  654.  
  655.         The alternative set can also be made empty by using cut to rule
  656.         out alternatives, as in the following replacement for "fact_iter":
  657.  
  658.         [32]        fact_iter(N,FactN,I,J) :-
  659.                                      I < N,
  660.                                      NewI = I+1,
  661.                                      NewJ = J*NewI,
  662.                                      !,
  663.                                      fact_iter(N,FactN,NewI,NewJ).
  664.  
  665.                     fact_iter(N,FactN,N,FactN).
  666.  
  667.         Here the recursive call occurs in the first clause, but the cut
  668.         guarantees that the second clause need not be considered as an
  669.         alternative.
  670.  
  671.  
  672.  
  673.  
  674.                                                                      13
  675.  
  676.         Because "NewI = I+1" and "NewJ = J*NewI" are deterministic, the
  677.         cut can equally well be placed before them, as follows:
  678.  
  679.         [33]        fact_iter(N,FactN,I,J) :-
  680.                                      I < N,
  681.                                      !,
  682.                                      NewI = I+1,
  683.                                      NewJ = J*NewI,
  684.                                      fact_iter(N,FactN,NewI,NewJ).
  685.  
  686.                     fact_iter(N,FactN,N,FactN).
  687.  
  688.         Note that [32] and [33] ought to be more efficient than [31]. The
  689.         first clause of [31] succeeds only on the last iteration; the rest
  690.         of the time, the first clause fails and control proceeds to the
  691.         second clause. Thus, almost every iteration must try both clauses.
  692.         In [32] and [33], the order of the clauses is reversed, so that
  693.         the first clause is the one that will almost always succeed.
  694.         Moreover, this clause contains a cut so that whenever it succeeds,
  695.         no other clause will be tried. The result is that, in [32] and
  696.         [33], only one clause -- the last one -- is tried on every
  697.         iteration except the last.
  698.          
  699.         In actual tests using Turbo Prolog on an IBM PC, the times taken
  700.         to compute the factorial of 200 were 0.58 second for [31] and 0.54
  701.         second for [32] and [33]. The gain in efficiency was small because
  702.         the time saved by omitting the unnecessary test was only slightly
  703.         greater than the time needed to execute the extra cut. The gain
  704.         would have been much larger if the unnecessary clause had
  705.         contained time-consuming computations.
  706.  
  707.         References
  708.  
  709.         Abelson, Harold, and Sussman, Gerald Jay (1985) Structure and
  710.           Interpretation of Computer Programs. Cambridge, Massachusetts:
  711.           MIT Press.
  712.  
  713.         Clocksin, W. F., and Mellish, C. S. (1984) Programming in Prolog.
  714.           Second edition. Berlin: Springer-Verlag.
  715.  
  716.         Dijkstra, E. W. (1975) Guarded commands, nondeterminacy and formal
  717.           derivation of programs. Communications of the ACM 18.8:453-457.
  718.  
  719.         Kluzniak, Feliks, and Szpakowicz, Stanislaw (1985) Prolog for
  720.           Programmers. London: Academic Press.
  721.  
  722.         Turbo Prolog (1986) Version 1.0. Scotts Valley, California:
  723.           Borland International.
  724.     does not mean that