prolog, test(X, Y, Z) :- Y is X + Z - prolog

How to get Y and Z in prolog, when I only know X?
For example:
test(X, Y, Z) :- X is Y + Z.
but error:
?- test(2, Y, Z).
ERROR: is/2: Arguments are not sufficiently instantiated

It's not possible, because you can choose Y to be anything you want and them compute Z or vice versa.
Although if you know that Y and Z are from some limited set (e.g. positive integers less than 5), you can do something like:
valid_number(1).
valid_number(2).
valid_number(3).
valid_number(4).
test(X, Y, Z) :- valid_number(Y), valid_number(Z), X is Y + Z.

You have to pass them as arguments. Prolog arithmetic (is/2) is not a magic wand, its right argument must be fully instantiated (no variables) before it can be evaluated.
If you want the predicate to work in several "directions", with multiple combinations of ground terms and variables, you'll want to use Constraint Logic Programming, but that's a rather advanced area of logic programming. In CLP on finite domains, you can say
:- use_module(library(clpfd)). % this differs between implementations
test(X,Y,Z) :- X #= Y + Z.

Related

prolog predicate that adds 2 numbers in successive notation and getting the result in Z also in successive notation

add(0,Y,Y).
add(s(X),Y,Z):-
add(X,Y,Z1),
Z is s(Z1).
why always resulting in false
why is the compiler telling me Arithmetic : 's(_2676)' is not a function
Your are confusing predicate calls with compound terms. You have not defined s/1 predicate. So the compiler throws an error. is is not a generic assignment, it is a arithmetic evaluator. You should use = instead.
The following should work. Here when I write s(X), this is not a predicate call but a compound term.
add(0, X, X).
add(s(X), Y, Z) :- Z = s(Z1), add(X, Y, Z1).
or this
add(0, X, X).
add(s(X), Y, s(Z)) :- add(X, Y, Z).
?- add(s(s(s(0))), s(s(0)), X).
X = s(s(s(s(s(0))))).

Prolog encoded integers, less/2(X, Y) predicate

A question states the following:
In Prolog, non-negative integers can be encoded as numerals given by 0 and its successors (with, for example, the numeral s(s(s(0))) encoding 3).
numeral(0).
numeral(s(X)) :- numeral(X).
Define the predicate less/2(X, Y) that holds when X and Y are numerals encoding non-negative integers x and y such that x < y. For example,
?- less(0, s(0)).
yes.
?- less(s(s(0)), s(s(0))).
no.
I have been able to come up with a solution for this question, however, it suffers from a limitation. Here is my solution:
less(X, s(X)) :- numeral(X).
less(X, Z) :- less(X, Y), less(Y, Z).
This solution correctly outputs a yes for inputs that satisfy this predicate. However, for inputs that expect a no, this solution seems to enter an endless recursion of some sort, and the program just keeps running, rather than outputting a no.
Please help.
I would do it like this:
less(0, s(Y)) :- numeral(Y).
less(s(X), s(Y)) :- less(X, Y).
?- less(0, s(0)).
true.
?- less(s(s(0)), s(s(0))).
false.
The idea is that 0 is less than any s(Y), where Y is a numeral. If X is not 0, then X is s(X'), and X = s(X') is less than Y = s(Y') iff X' is less than Y'.
This does only work if both X and Y are numerals. If X is not a numeral then it will get stuck somewhere in the recursion and "returns" false. Same for Y, except that there need to be a test at the end if the rest of Y is a numeral.
Try this:
less2(X, s(X)) :- numeral(X).
less2(X, s(Y)) :- less2(X,Y).
Seems to work for me; your solution could recurse endlessly though, because if there exists no value of Y between X and Z it will simply try everything under the sun.

Prolog- find any number above 0

I'm a bit surprised about this Prolog error. For p(X) :- X > 0:
?- p(X).
ERROR: Arguments are not sufficiently instantiated
I assumed this would unify X with some value above 0.
Could someone explain why my intuition might be off here?
Generally, arithmetic in prolog isn't reversible, but you can use something like the following code snippet from the same source:
better_add(X,Y,S) :- not(var(X)), not(var(Y)), not(var(S)),
Z is X + Y, Z=S.
better_add(X,Y,S) :- not(var(X)), not(var(Y)), var(S),
S is X + Y.
better_add(X,Y,S) :- not(var(X)), var(Y), not(var(S)),
Y is S - X.
better_add(X,Y,S) :- var(X), not(var(Y)), not(var(S)),
X is S - Y.

Can I use integers as parameters?

How can I know if a person X is descendant of a person Y given the descendancy degree?
I've tried this:
descendant(X, Y, 1) :- son(X, Y).
descendant(X, Y, Degree) :- son(X, Z) , descendant(Z, Y, Degree-1).
Where son(X, Y) returns yes if X is son of Y. If Degree == 1 it returns the correct answer but for descendant(X, Y, 2), for instance, should return yes if X is grandson of Y but returns no.
1) Naming: Does son(X,Y) mean "X is the son of Y"—or vice-versa?
son_of(X,Y) is better.
2) Exploit successor-arithmetics: We don't need to do general arithmetics here... we only need to count.
So let's start in the beginning...
child_of(abel, adam). % from source
child_of(abel, eve).
child_of(cain, adam).
child_of(cain, eve).
child_of(enoch, cain).
child_of(irad, enoch).
child_of(mehujael, irad).
child_of(methushael, mehujael).
child_of(lamech, methushael).
child_of(jabal, lamech).
child_of(jabal, adah).
child_of(jubal, lamech).
child_of(jubal, adah).
child_of(tubal_cain, lamech).
child_of(tubal_cain, zillah).
child_of(naamah, lamech).
child_of(naamah, zillah).
child_of(seth, adam).
child_of(seth, eve).
child_of(enos, seth).
child_of(kenan, enos).
child_of(mahalalel, kenan).
child_of(jared, mahalalel).
child_of(enoch, jared).
child_of(methuselah, enoch).
child_of(lamech, methuselah).
child_of(noah, lamech).
child_of(shem, noah).
child_of(ham, noah).
child_of(japheth, noah).
Based on child_of/2 we first define ancestor_of/2—this should be nothing new to you!
ancestor_of(Y, Z) :-
child_of(Z, Y). % If Z is a child of Y ...
% then Y is an ancestor of Z.
ancestor_of(X, Z) :-
child_of(Z, Y), % If Z is a child of Y ...
ancestor_of(X, Y). % and X is an ancestor of Y ...
% then X is an ancestor of Z.
Next, we add an additional parameter indicating the distance.
We use s/1 terms to represent natural numbers and add a new argument to ancestor_of/2:
ancestor_of_dist(Y, Z, s(0)) :-
child_of(Z, Y). % If Z is a child of Y ...
% then Y is an ancestor of Z with distance = 1."
ancestor_of_dist(X, Z, s(N)) :-
child_of(Z, Y), % If Z is a child of Y ...
ancestor_of_dist(X, Y, N). % and X is an ancestor of Y with distance N ...
% then X is an ancestor of Z with distance N+1.
So ... who is grandparent of whom?
?- ancestor_of_dist(X, Z, s(s(0))).
X = adam, Z = enoch
; X = eve, Z = enoch
; X = cain, Z = irad
; X = jared, Z = irad
; X = enoch, Z = mehujael
; ...
; X = lamech, Z = japheth
; false.
Prolog is not a functional language. Thus, the Degree-1 term is not interpreted and evaluated as an expression. For Prolog, Degree-1 is just a compound term with two arguments. That can be made clear using the standard write_canonical/1 predicate, which writes a term without using operator notation:
?- write_canonical(Degree-1).
-(_,1)
true.
Write instead:
descendant(X, Y, 1) :-
son(X, Y).
descendant(X, Y, Degree) :-
son(X, Z) ,
descendant(Z, Y, Degree0),
Degree is Degree0 + 1.
The is/2 standard built-in predicate unifies the left argument with the value of the arithmetic expression in the right argument.
P.S. Note that the alternative descendant/3 predicate definition I suggest will solve the problem you described but it is not an efficient definition as it is not a tail-recursive definition. I.e. the recursive call in the second clause is not the last call in the clause body. This issue can be easily solved, however, by using an accumulator.

Basic prolog issue with syntax of statement

I'm sort of a beginner to Prolog and I have a quick question. I've written a sister_of/2 predicate that goes like this:
sister_of(X, Y) :-
female(X),
parents(X, Z, W) == parents(Y,Z,W),
X \= Y.
I read this as X is a sister of Y if X is a female and the parents of X which are Z W are the same parents of Y, Z W and X and Y are not the same person. This isn't running for some reason though, so it must be a syntax issue, some insight would be fantastic. Thank you.
Prolog is not a functional language, it's a relational language. You define predicates (i.e. relations), not functions. Thus, your parents(X, Z, W) == parents(Y,Z,W) is just comparing two terms, parents(X, Z, W) and parents(Y,Z,W) for equality. Assuming that a parents/3 predicate is also defined, you want something like:
sister_of(X, Y) :-
female(X),
parents(X, Z, W),
parents(Y, Z, W),
X \= Y.
Well, you began the construction of reasoning alright, but failed during the comparison. Here's what you've missed:
sister_of(X, Y) :-
female(X),
parents(X, Z, W),
parents(Y, Z, W),
X \= Y.
Now the reasoning goes as follows:
X is a sister of Y;
if X is a female;
if X has parents Z and W;
if Y has parents Z and W;
and, of course, X is not Y, so that X is not a sister of itself.
Notice that, the comparison you performed earlier is not necessary (and in fact, does not mean what you expected), since Z and W become limited to be the parents of X in step 3. This means that, Z and W already have a determined value after step 3 -- they are bound, in other words.
After that, in step 4, Y can only assume the same value of X, or some other value that makes parents(Y, Z, W) true. Finally, you remove the cases where X == Y in step 5, which gives you a valid definition of sister_of(X, Y).

Resources