3

There are two possible rules for addition in Prolog, with different termination properties according to cTI:

  1. cTI reports sum(A,B,C)terminates_if b(A);b(C). for the following rule:
sum(0, Y, Y).
sum(s(X), Y, s(Z)) :-
  sum(X, Y, Z).
  1. cTI reports sum(A,B,C)terminates_if b(A),b(B);b(C). for the following rule (X and Y are swapped):
sum(0, Y, Y).
sum(s(X), Y, s(Z)) :-
  sum(Y, X, Z).

The difference can be observed for instance by executing the query sum(X, 0, Z). with SWISH, the online SWI-Prolog implementation of Prolog.

It returns the following solutions for the first rule:

?- sum(X, 0, Z).
   X = Z, Z = 0
;  X = Z, Z = s(0)
;  X = Z, Z = s(s(0))
;  X = Z, Z = s(s(s(0)))
;  X = Z, Z = s(s(s(s(0))))
;  …

And it returns the following solutions for the second rule:

?- sum(X, 0, Z).
   X = Z, Z = 0
;  X = Z, Z = s(_1302)
;  false.

Which of these two rules is correct?

Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
  • 1
    In the second definition: `2 unresolved: [sum(b,f,f),sum(f,b,f)].`! So again this is a weakness of cTI. By unfolding the definition once [you get the optimal result](http://www.complang.tuwien.ac.at/cti/cgi/cti?texta=sum%280%2C+Y%2C+Y%29.%0D%0Asum%28s%28X%29%2C+Y%2C+s%28Z%29%29+%3A-+sum%28Y%2C+X%2C+Z%29.%0D%0A%0D%0Asump%280%2C+Y%2C+Y%29.%0D%0Asump%28s%28X%29%2C+Y%2C+s%28Z%29%29+%3A-+sumi%28Y%2C+X%2C+Z%29.%0D%0A%0D%0Asumi%280%2C+Y%2C+Y%29.%0D%0Asumi%28s%28X%29%2C+Y%2C+s%28Z%29%29+%3A-+sump%28Y%2C+X%2C+Z%29.) which is **sump(A,B,C)terminates_if b(A);b(B);b(C).** [Voir](/q/27202175/772868). – false Aug 04 '21 at 17:10

1 Answers1

3

When discussing various versions of the same program, it helps a lot to rename those versions such that they can cohabit in the same program:

sumA(0, Y, Y).
sumA(s(X), Y, s(Z)) :- sumA(X, Y, Z).

sumB(0, Y, Y).
sumB(s(X), Y, s(Z)) :- sumB(Y, X, Z).


?- sumA(X, 0, Z).
   X = 0, Z = 0
;  X = s(0), Z = s(0)
;  X = s(s(0)), Z = s(s(0))
;  X = s(s(s(0))), Z = s(s(s(0)))
;  ... .
?- sumB(X, 0, Z).
   X = 0, Z = 0
;  X = s(_A), Z = s(_A).

(Above output is from Scryer, which is better readable)

Before looking at the concrete definitions, think of the set of solutions that we expect for X and Z. Both should be the same, and they should describe all natural s(X)-numbers 0, s(0), s(s(0)) ... So we have infinitely many solutions. How shall we, finite beings with our finite Prolog systems, describe infinitely many solutions? Well, we can give it a try and just start1. That's what we see in sumA. What is nice here, is that each and every answer is actually a solution (that is, there are no variables remaining2). Just a pity that the program does not terminate (universally). At least it produces all solutions in a fair manner. Wait long enough and also your favorite solution3 will appear.

In sumB that infinite set of natural numbers is enumerated in a quite different manner. First, we get a solution for 0 and then we get a single answer which includes all other numbers ≥ 1. So we have compressed this infinite set into a single variable! That's the power of logic variables. Of course, we paid a tiny price here, for now we also include really everything in the argument of s(_A). Everything, including s(nothing).

?- Z = s(nothing), sumA(Z, 0, Z).
   false.
?- Z = s(nothing), sumB(Z, 0, Z).
   Z = s(nothing).

Which of these two rules is correct?

Both sumA and sumB are correct. And sumB as long as we can distinguish our numbers from other terms (that's what roughly corresponds to a well typed program).

But which one is preferable? It all depends. Usually the predicate will be used in some context. Maybe a subsequent goal will only terminate if one of its arguments is ground. In this case, sumA may be preferable. If there is no further goal then sumB is always preferable. It all depends a bit.

What is most important to see is that some of the infinities of solutions can be elegantly subsumed with logic variables thereby improving the termination property. For more complex situations this will not be enough but then constraints will be attached to those variables.


1) And don't be upset if we get a resource_error(memory), it's just a finite system.


2) And no residual constraints to be precise.


3) My favorite numbers are 7^7^7 and 9^9^9. With current implementations this will take some time and space.

false
  • 10,264
  • 13
  • 101
  • 209
  • Thanks false! ‘What is most important to see is that some of the infinities of solutions can be elegantly subsumed with logic variables thereby improving the termination property.’ I thought that termination meant *finite* result set. So you claim that it actually means finite *representation* of the result set, allowing *infinite* result sets provided that the interpreter is able to express them with logic variables? – Géry Ogam Aug 04 '21 at 23:14
  • 1
    The common notion is **answers** represented in particular by **answer substitutions** which are capable of representing an infinity of solutions. [Here](/a/13533023/772868), and [here](/a/26450510/772868) are [some more](/search?q=user%3A772868+%5Bprolog%5D+answer+solution). – false Aug 05 '21 at 09:51
  • I see: the evaluation of a goal returns a sequence of *answers*; each answer represents a subset of *solutions*; the union of the solution subsets is the solution set of the goal. A goal *terminates* when it has a *finite* answer sequence (e.g. `sump(A,B,C)terminates_if b(A);b(B);b(C).` means that the goal `sump(A, B, C).` has a finite answer sequence when `A`, `B`, or `C` is bound—despite having an infinite solution set). Thanks for the links and explanation. – Géry Ogam Aug 05 '21 at 14:26
  • 1
    @Maggyero: You can define termination as a finite answer sequence, yes. But then, that is already too much detail. Universal termination in Prolog is simply `G_0, false` terminating. Often the precise answers are highly distracting if you are interested in termination **only**. – false Aug 05 '21 at 15:02
  • An argument in favor of `sumB` that I think about is that its first and second arguments are symmetric with respect to termination (`sumB(A,B,C)terminates_if b(A),b(B);b(C).`). – Géry Ogam Aug 05 '21 at 15:23
  • 1
    @Maggyero: All three arguments are symmetric w.r.t. termination. The actual termination condition is `sumB(A,B,C)terminates_if b(A);b(B);b(C).` – false Aug 05 '21 at 15:25
  • Yes you are right. Whereas cTI gives an asymmetry with respect to termination for the second argument of `sumA`: `sumA(A,B,C)terminates_if b(A);b(C).` – Géry Ogam Aug 05 '21 at 16:42
  • 1
    In `sumA/3` the second argument is [termination neutral](http://www.complang.tuwien.ac.at/cti/cgi/cti?texta=sumA(0%2C+Y%2C+Y).%0D%0AsumA(s(X)%2C+Y%2C+s(Z))+%3A-+sumA(X%2C+Y%2C+Z).&tna=only). – false Aug 05 '21 at 17:03
  • Can I request again your expertise on [this Prolog post](https://stackoverflow.com/q/68731776/2326961)? – Géry Ogam Aug 10 '21 at 18:20