I guess I have some bigger problem in understanding prolog, but since I can't quite formulate it, I focus on single problem
I want to create a rule natural(X)
that is true if X
is 1,2,3,4,...
More importantly, I want both: natural(5)
to be true and natural(X)
to output X=1; X=2; ...
So, I explain rule as follows (pseudologic):
natural(1) must be true
natural(X) is true if natural(X-1) is true
or, in terms of prolog:
natural(1).
natural(X) :- natural(X-1).
but I get a problem - if I try natural(5)
I get infinite recursion
debugger says that program evaluates:
natural(5)
natural(5-1)
natural(5-1-1)
natural(5-1-1-1)
natural(5-1-1-1-1)
natural(5-1-1-1-1-1)
natural(5-1-1-1-1-1-1)
...
I guess the problem is in X-1
not being evaluated?
Let's try to fix that:
natural(1).
natural(X) :-
Y is X-1,
natural(Y).
now, natural(5)
works as expected
but, if I use natural(X)
I get X=1; Exception: Arguments not sufficiently instantiated (Y is X-1)
ok, I guess the problem is we try to evaluate stuff that can be without value yet
If I try to use Y = X-1
we return to first problem. Y == X-1
returns false
The only solution that I found to work was switching lines and definition order:
natural(1).
natural(X) :-
natural(Y),
X is Y+1.
Changing last line to =
gives "+1+1+1..." results. ==
just fails.
This solution works great in generating X=1; X=2; ...
, but when I use it as check (natural(5)
), it goes in "0,(0,1),(0,1,2),(0,1,2,3),..." order. Yes I get correct result, but the path there is long and not what I would've imagined.
I would've stopped here, if I haven't seen the faster way of checking for natural(5) in previous solution.
So, what is better way of creating this rule have I missed?
I guess one way would be separating "true/false" queries from generator queries... But is there a way to make it "evaluate if possible to evaluate", i.e. separate only-constants from has-variables? var(X-1)
is false somehow...
(is)/2
it is very hard and incomplete. Then, uselibrary(clpfd)
, which is even more natural. Think of:X #>= 0
. – false