The Cut Predicate
In this section, we will provide two examples of predicate definitions. These definitions look correct, but when we use it with backtracking, it will be erroneous.
In this example, we will use a predicate larger. In the first two arguments, it takes the larger value. It returns the answer as the third argument value.
In this, we search the clauses from 'top to bottom'. If X is less than or equal to Y, the second clause will only be assumed to apply. In the following example, the first two arguments have 7 and 5 value, and when we test the definition with 7 and 5, it gives a correct answer as follows:
At this stage, if the system is forced by the user to backtrack, it will examine the second clause for larger, and after that, it will generate an incorrect second answer.
In this example, we will use the definition of sumto/2 predicate. This definition looks correct, but it has a serious flaw.
The goal sumto(N, S) is used to calculate the sum of integers from 1 to N. It generates the result as the Y's value.
If backtracking is forced, due to this, the system will crash and generate a cryptic error message like 'stack overflow'. When whilst evaluates the goal sumto(3, S), the solution for sumto(1, S) is found by the Prolog. The first clause is rejected while backtracking. Now, the system uses the second clause to satisfy the goal. This causes it to subtract one from one, and then the system evaluates the goal sumto(0, S). When the system does this in turn, it evaluates sumto(-1, S1), then sumto(-2, S1), then sumto(-3, S1), and so on. This process will stop when the system runs out of memory.
In the definition of predicates, Example 1 and Example 2 could both be remedied using the additional goals. For example, for this, we will change the definition of larger in the second clause as follows:
We will also change the definition of sumto in the second clause as follows:
It is considerably more difficult to identify such additional terms in other cases.
Using the cut, we can avoid unwanted backtracking. The cut is represented by !. In the body of a rule, when ! goal evaluates for the first time, it always succeeds. It always fails while backtracking. The further evaluation of the current goal always fails, so it prevents this.
Example 1 (revised)
Example 2 (revised)
When we use backtracking over cut, it is abandoned to evaluate the current clause of sumto or larger. It is used to prevent the evaluation of any other clauses for that predicate.
This incorrect program uses a classify/2 predicate. This predicate is used to classify a number, which can be zero, positive, and negative. In the following program, the first clause deals with zero value of the first argument. The second clause is used to deal with a negative value. The third clause is used to deal with a positive value.
By changing the third clause, the above can be rectified as follows:
Or we can also use the cut as follows:
Example 3 (revised)
So, we have rectified all the incorrect programs rather than using cut. We add an additional goal to one of the clauses. This approach is much better than cut. A more difficult case is shown by the following program.
In the following program, we are going to use a predicate go. This predicate is used to prompt the user repeatedly for input until the user enters a positive number. In the definition of predicate classify, the lack of cuts leads to incorrect answers.
The expected behavior of go is given by changing the definition of classify to one, which is defined in the above Example 3 (revised).
Example 4 (revised)