Prolog: Chaining multiple rules - prolog

So I am an absolute beginner in Prolog. I am learning recursion at the moment and this is what I got until now on my task.
dance(start).
dance(forward(T)) :- dance(T).
dance(backward(T)) :- dance(T).
count(start,0,0).
count(forward(X),succ(Y),Z) :- count(X,Y,Z).
count(backward(X),Y,succ(Z)) :- count(X,Y,Z).
greater(succ(0),0).
greater(succ(Y),succ(Z)):-greater(Y,Z).`
Summary of what this is supposed to do: There can be dances starting with the "start" and then either forward or backward addition per recursion. In count, I managed to be able to count the amount of forward and backward in a given sequence and save them in the "succ" notation and in greater I want to compare two of such "succ" numbers. And greater shall be true if the first argument is larger (consists of more "succs" than the second argument.
Now my task is to write a new rule "more(X)" which is true if the sequence X (build from dance) has more forward than backward in it. I think I have all the subtasks I need for it but now I am helpless with chaining them together because until now I only had 2 rules with the same amount of parameters but in this case, I got one with one, two, and three parameters. The solution should be something like this
more(X):-greater(Y,Z)
but how do I get my "succ" umbers from "count" to "greater" and the given sequence X to "count"? I do have to change some of the rules otherwise count is never called, right?
So it should be more like more(X):-greater(count(X,Y,Z)) ?
But like this, I would have to change the greater rules to be able to "get" this type of parameter.
Example query ?- more(backward(forward(start))).
false.
?- more(forward(start)).
true.

Your dance/1 and count/3 predicates seems correct.
If you want "greater" where greater(X, Y) means that X is greater than Y, you'd write:
greater(succ(_), 0).
greater(succ(X), succ(Y)) :- greater(X, Y).
Your solution checks if X is exactly one greater than Y.
Note that nothing is greater than 0.
If you implement more/1 in terms of count/3 and greater/2, you'd write:
more(X) :-
count(X, Forward, Backward),
greater(Forward, Backward).

So it should be more like more(X):-greater(count(X,Y,Z)) ?
No, you are writing that as if it is Python and greater(count(X,Y,Z)) will call greater(...) on the return from count. Prolog predicates are not function calls, and count(...) does not return anything in that way.
The result of the count is Y and Z. (These names you are using could be clearer). Do the count, and then after, use the Y and Z for something else.
count(X,Y,Z),
greater(Y,Z)
The comma being AND; "this code works if count of X is Y and Z AND Y is greater than Z".

Related

Simple Prolog predicate - statement is always evaluated as false

I've just started Prolog and truly wonder why the following lines, specifically the 'is' part, always produces false:
highest(L) :-
path(_,_,Z),
Z >= L,
L is Z.
highestWrap :-
highest(0).
highestWrap is called.
Thanks in advance and have a beautiful day!
Unless there is a path with length 0, this will not work, and even then, it will likely not yield what you want: it will just say true.
In Prolog variables can only be set once, that means that if L is set to 0, then it remains 0, unless you backtrack over that assignment.
Here it thus means that you call highest(0), next you instruct Prolog to call path(_, _, Z) and this can result in zero, one or more solutions. In case there are no path(_, _, Z)s, then the call will fail. But in case there are, then Z will (if I make correct assumptions about the predicate), have a numerical value, for example 7.
Now the condition Z >= L of course holds in that case (if Z is 7), so that is nog the problem. But now you specify L is Z. That thus means that you call 0 is 7. The is/2 [swi-doc] predicate aims to solve the expression of the second argument (that expression is 7 in the example, so there is not much to solve), and then aims to unify it with the term on the left side. But since 0 is not equal to 7 that fails.
If you want to obtain the highest path, you can for example make use of the aggregate [swi-doc] library:
:- use_module(library(aggregate)).
highest(L) :-
aggregate(Max(Z), path(_,_,Z), Max(L)).
You can then call it with higest(X) to unify X with the highest value for Z in a call to path(_, _, Z).

decrement the same variable in Prolog

Something like this:
decr(X, X) :-
X is X-1.
I want to use it for decrement a number in the parent rule , if this number equal 0 for example, the parent rule return false.
Prolog is declarative: one of the properties of a declarative language is that once you set a variable, you cannot give it another value anymore. In Prolog backtracking can of course "unground" a variable and furthermore you can assign a partially grounded expression to a variable (like X=f(1,_)), but when you move deeper into the call stack, each expression can only be grounded further.
As a result: you have to use another variable. Like:
decr(X,NX) :-
NX is X-1.
This is also logical: here you defined decr(X,X) and since the argument of predicates in Prolog have no input/output direction, it is unclear whether you want to call it like decr(4,3), decr(X,3), decr(4,X) or decr(X,Y). So how can Prolog "know" that your second X is supposed to be the "new X"? It is thus a "fundamental property" of Prolog you cannot use X, call a predicate, and all of a sudden X has a different value (it can however - as said before - be grounded further, but an integer cannot be grounded further).
The reason why it will always error or fail is because, either X is not instantiated: (like decr(_,_)) in which case Prolog cannot calculate X is _-1, or you have given one of the argument a number (decr(X,3), decr(4,X) or decr(3,3)), but in that case you ask that both operands can unify (since they are both X) and are off by one at the same time, which is a contradiction.
As already mentioned, you can't reassign variables in Prolog, but the closest thing available out-of-box to what you apparently want is succ/2 predicate:
?- succ(1, X).
X = 2.
?- succ(X, 5).
X = 4.
The next closest is probably plus/3:
?- plus(1, 2, X).
X = 3.
?- plus(1, X, 3).
X = 2.
?- plus(X, 2, 3).
X = 1.

Prolog sequences

Good Day,
I have a task (not homework), but test preparation question. Given a value of n where n > 0. I need to find out what 3**n value is. I do have something that works.
% expo
expo([],[]).
expo([X|T], [Y|Result]):-
number(X),
Y is 3 ^ X,
expo(T,Result).
expo([ThrowAway|Tail], [ThrowAway|Result]):-
expo(Tail,Result).
last([X]):-
write("M = "),
write(X).
last([Y|Tail]):-
last(Tail).
do_list(N) :-
findall(Num, between(0, N, Num), L),
expo(L, E),
last(E).
When I run this at the console:
do_list(4).
M = 81
true.
So it does give me what I want. But is a recursive solution necessary? I just want to generate a sequence of numbers and use those numbers as my exponent which I have done, but I had to create two lists to this.
Ideally, I'd like to do:
do_list(4, M).
M = 81
true.
Is this possible to do this without two lists? Is it possible without recursion? I'm new to Prolog, so it's taking me a little getting used to "thinking" in Prolog.
TIA,
coson
If you want to do something in all elements of a list then yes most of the times you need recursion (except from cases like when you use predicates like fundall/3 which does the recursion ...).
If you want to return your result in an argument and not just print it then you need for the above predicate two lists (one is the input and the other one is the output).
Though I don't understand why not just writing:
find_pow(Input,Output):-Output is 3^Input.
From what I understood you calculate 3^i for every i<=n and keep last element which could be done independently. So if I understood corrctly what you're trying to do, this could be done without using lists and recursion (if you use predefined pow function ^ else if you write a predicate that computes the power 3^n then you would use recursion... ).
Example:
?- find_pow(4,X).
X = 81.

Prompt does not come back

I try to do some exercise - to represent numbers in "s representation" which means '0' is zero, s(0) is 1, s(s(0)) is 2 and so on.
I tried to write predicate for adding "s numbers":
the predicate s2int convert "s number" to int.
s2int(0, 0).
s2int(s(X), Y) :-
s2int(X, Y1),
Y is 1 + Y1.
add(X, Y, Z) :-
s2int(X, SX),
s2int(Y, SY),
s2int(Z, SZ),
SZ is SX + SY.
When I query add it writes the correct answer but the prompt does not come back.
What's the problem?
Your definition of add/3 works fine, and also terminates, if all three arguments are given. If you leave one of them as a variable, one of the goals s2int(XYZ, SXYZ) has then two uninstantiated variables as arguments. It describes thus an infinitely large set, whose complete enumeration takes infinitely long.
Not sure what you are after, but probably you want to define add/3 for successor arithmetics. You can do this, without resorting to the 0,1,2 integers! Try it! Otherwise search of successor-arithmetics.

Sum of a list in prolog

I'm reading 'the art of prolog' book and I found an exercise that reads 'Define the relation sum(ListOfIntegers,Sum) which holds if Sum is the sum of the ListOfIntegers, without using any auxiliary predicate' .I came up with this solution:
sum([],Sum).
sum([0|Xs], Sum):-sum(Xs, Sum).
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Which does not work exactly as I would want it to.
?- sum([s(s(0)),s(0),s(s(s(0)))],X).
true ;
false.
I was expecting X to be
s(s(s(s(s(s(0))))))
I thought that the problem is that I have to 'initialize' Sum to 0 in the first 'iteration' but that would be very procedural and unfortunately I'm not quite apt in prolog to make that work.
Any ideas or suggestions?
Your first clause should read
sum([], 0).
With that change, the vacuous true return goes away and you're left with one problem: the third clause reverses the logic of summation. It should be
sum([s(X)|Xs], s(Sum)) :- sum([X|Xs], Sum).
because the number of s/1 terms in the left argument to sum/2 should be equal to the number of them in the right argument.
The best way to localize the problem is to first simplify your query:
?- sum([0],S).
true.
?- sum([],S).
true.
Even for those, you get as an answer that any S will do. Like
?- sum([],s(s(0))).
true.
Since [] can only be handled by your fact, an error must lie in that very fact.
You stated:
sum([], Sum).
Which means that the sum of [] is just anything. You probably meant 0.
Another error hides in the last rule... After fixing the first error, we get
?- sum([0],Sum).
Sum = 0.
?- sum([s(0)],Sum).
false.
Here, the last clause is responsible. It reads:
sum([s(X)|Xs], Sum):-sum([X|Xs],s(Sum)).
Recursive rules are relatively tricky to read in Prolog. The simplest way to understand them is to look at the :- and realize that this should be an arrow ← (thus a right-to-left arrow) meaning:
provided, that the goals on the right-hand side are truewe conclude what is found on the left-hand side
So, compared to informal writing, the arrows points into the opposite direction!
For our query, we can consider the following instantiation substituting Xs with [] and X with 0.
sum([s(0)| [] ], Sum) :- sum([0| []],s(Sum)).
So this rule now reads right-to-left: Provided, sum([0],s(Sum)) is true, ... However, we do know that only sum([0],0) holds, but not that goal. Therefore, this rule never applies! What you intended was rather the opposite:
sum([s(X)|Xs], s(Sum)):-sum([X|Xs],Sum).
I'm not really following your logic, what with all the seemingle extraneous s(X) structures floating about.
Wouldn't it be easier and simpler to do something like this?
First, define your solution in plain english, thus:
The sum of an empty list is 0.
The sum of a non-empty list is obtained by adding the head of the list to the sum of the tail of the list.
From that definition, the prolog follows directly:
sum( [] , 0 ) . % the sum of an empty list is 0.
sum( [X|Xs] , T ) :- % the sum of an non-empty list is obtained by:
sum( Xs , T1 ) , % - first computing the sum of the tail
T is X + T1 % - and then, adding that the to head of the list
. % Easy!

Resources