1

In Prolog, I would like to implement a trivial logical induction predicate i as (1):

i(0).
i(N) :- i(N-1).

or (2):

i(0).
i(N+1) :- i(N).

But this doesn't work; with (1), query i(3). causes a stack overflow; with (2), i(3). returns false.

Instead, I have to do (3):

i(0).
i(N) :- M is N-1, i(M).

Naively, the difference between (3) and (1) seems like a trivial syntactic shift, and declaring intermediate variables feels like a hassle in bigger programs. What's the reason behind the Prolog compiler rejecting (1) and (2), does a work-around exist, and why do (1) and (2) behave differently?

silver
  • 160
  • 7
  • `N-1` is a *term* that can also be expressed as `-(N, 1)`, rather than an arithmetic expression, as seen in e.g. https://www.swi-prolog.org/pldoc/man?section=pairs – brebs Jul 05 '22 at 11:44
  • You write "trivial logical induction" but then you start doing arithmetic on integers. I think I understand what you are after but maybe you should be a bit more precise with the exact wording, before I dare and try to answer. Like, what is your "i" _supposed to do_? – TA_intern Jul 05 '22 at 12:54
  • The prolog compiler did not reject your code. It compiled it and ran it, as you report yourself in your question. It just didn't do what you _wished_ it would do, but I can't guess what you wished for and apparently the machine couldn't either. – TA_intern Jul 05 '22 at 12:57

1 Answers1

1

Surprisingly, it isn't a trivial syntactic shift. N-1 in Python is always arithmetic; you can replace 5-1 with 4 and "cat"-1 is an error.

In Prolog dash is not arithmetic, it's a term connecting Left/Right with a dash. You can write "cat"-1 ("cat dash one") to pair two things up and pass them around together, and people do:

?- "cat"-1 = N-1.    % unify against it,
N="cat"              % reason that N must be "cat" for this to be true.

?- N-1 = -(N,1)      % rewrite it in normal name(X,Y) format,
true                 % where dash is the name.


% make a list of pairs joined with dash:

?- pairs_keys_values(Ps, [cat,dog,cow,fish], [1,2,chicken,N-1])
Ps = [cat-1, dog-2, cow-chicken, fish-(N-1)]

So people wanted a way to wedge math into a logical relation language, and came up with a predicate which knows how to do calculation on terms with the names + - / * and so on. A predicate like math_evaluate(Result, Term) and if you had it you could write it like Result math_evaluate N-1 so it looks neater. That math_evaluate predicate is is(Result, Term):

?- N=5, is(Result, N-1)
N = 5,
Result = 4

which you can write Result is N-1 in a similar way that you can rewrite -(N,1) as N - 1.

TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87