Sum of a list in prolog - 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!

Related

Prolog: Chaining multiple rules

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".

Repeat and Double elements in lists in Prolog

how can I write two predicates that are described below.
1) Define the double(X,Y) predicate, which is true if the list Y contains each of the elements X
repeated twice. Example: double([a,b],[a,a,b,b]) is true.
2) Define the predicate repeat(X,Y,N), which is true if the list Y contains each of the elements X
repeated N times. For example, for the question repeat([a,b],[a,a,a,b,b,b],3), Prolog answers true.
Could you give me the example of those predicates?
If you have repeat/3 you have double/2.
and thus:
multiple(X,N,R) :-
length(R,N),maplist(=(X),R).
repeat(Li,Lo,N) :-
maplist({N}/[Xi,Xo]>>multiple(Xi,N,Xo),Li,Nested),flatten(Nested,Lo).
But it doesn't run backwards due to the flatten/2 I think. Can that be improved?
double([], []).
double([X|Y], [X,X|Z]) :- double(Y,Z).
remove_if_same(_,R,0,R):- !.
remove_if_same(X,[X|Y],N,R) :- Nm1 is N-1,remove_if_same(X,Y,Nm1,R).
repeat([],[],_).
repeat([X|Xr],Y,N) :- remove_if_same(X,Y,N,R), repeat(Xr,R,N).
How double works?
If you've got two empty lists, then that is true, there is nothing to double from the first argument.
Otherwise, you're taking the head from the first list, and 2 head elements from the second list. If all these are the same (so if all are X) you're checking with recursion rest of elements, so accordingly Y and Z. So you'll check once again if lists are empty and so on, and if on any of the steps sth is not possible you return false.
About the repeat predicate, it's quite similar in reasoning.
2 things that I should explain:
The ! mark will make that the command-line interface(like swipl) will not search for other results of the remove_if_same. It would work same if we pass it to the repeat.
remove_if_same statement uses the accumulator (the 4th argument) to return at the end of the search the list without N same elements.

Prolog - confused about return results of recursive rule

I'm playing around with recursion in Prolog, and I'm confused. I am trying to write rules that can determine if a number is even or odd. I know that there are other stackoverflow questions about this, but I don't care about having a working solution, I am more interested in knowing why mine doesn't work.
Here are my rules:
even(0).
even(N) :- N>0, N1 is N-1, odd(N1).
odd(N) :- N>0, N1 is N-1, even(N1).
When I query even(0), I get returned 2 results. The first result is true, the 2nd is false. This also happens with odd(1), even(2), odd(3), etc. Why am I getting 2 return results? Shouldn't I just get 1?
When you query even(0), it succeeds as you have seen. But you've also seen it prompts you for more results because it left a choicepoint, which is a place in the logic where Prolog decides it can come back and explore other alternatives for a potentially successful query. Upon going back to the choicepoint and attempting to find more solutions, it does not find more, so it comes back "false" since it found no more solutions. So it did just find one solution, but the choice point caused backtracking after which it found no additional solutions. This is the case with your other successful queries as well.
You'll note that if you make a more general query, it gives an error (example taken from GNU Prolog):
| ?- even(N).
N = 0 ? ;
uncaught exception: error(instantiation_error,(>)/2)
| ?-
This is because you are using specific arithmetic expression operators that require that the variables be instantiated. These are relational operators like (>)/2 and the is/2 operator. You can make the solution more relational by using the CLP(FD) operators which are designed for reasoning with integers:
even(0).
even(N) :-
N #> 0,
N1 #= N-1,
odd(N1).
odd(N) :-
N #> 0,
N1 #= N-1,
even(N1).
Then you get a more general solution, which is more complete and more useful:
| ?- even(N).
N = 0 ? ;
N = 2 ? ;
N = 4 ? ;
N = 6 ? ;
...
| ?- odd(N).
N = 1 ? ;
N = 3 ? ;
N = 5 ? ;
N = 7 ?
...
If you know there is at most one answer, or if you only care about the first possible answer, you can use once/1 (examples taken from SWI Prolog here):
2 ?- even(2).
true ;
false.
3 ?- once(even(2)).
true.
4 ?- even(N).
N = 0 ;
N = 2 ;
N = 4 ;
...
5 ?- once(even(N)).
N = 0.
6 ?-
As expected, once(even(N)) terminates after finding the first solution.
The return values you have are correct. The point is how Prolog is evaluating predicates. When you query i.e.
even(2)
Prolog firstly evaluate that this predicate is Yes / true. When going through next possibility it return No / false, because it cannot find any more.
To check what exactly is performed under the hood go to:
https://swish.swi-prolog.org
on the left side type rules (i.e. odd/even) and on the query window type like 'odd(2)', but just before running click 'solutions'->'debug(trace)'. It will let you go step by step of what Prolog is doing.
Also please take a look at the successor example in tutorial below.
http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse9
from a link above, try such code for a reversed example:
numeral(0).
numeral(succ(X)) :- numeral(X).
Now evaluating numeral(0) for the first time return succ(0), another time succ(succ(0)) etc.
Each time next evaluation brings another possible solution for a query.
What Prolog does is a "depth-first search", which means Prolog walks through a decision tree until it either finds a solution and succeeds OR it fails. In either case a process called "backtracking" kicks in. Along the way, going through the tree of choices, Prolog keeps track of where it has MULTIPLE possible routes that could potentially satisfy the goal. Such a point in the decision tree is called a "choice point".
This means Prolog will
search ->
succeed or fail ->
go back to the last choice point ->
repeat until all possible paths have been tried
Given your program:
even(0).
even(N) :- N>0, N1 is N-1, odd(N1).
odd(N) :- N>0, N1 is N-1, even(N1).
We can clearly see TWO ways to satisfy even(0).. The first is the fact even(0) and the second is the recursive rule even(N). Prolog reads top to bottom, left to right so the first encounter is even(0). which is true, and the second is even(N). which goes through N-1 making the result N1 = -1, then goes through odd(N) making the result N1 = -2, which in unequal to even(0). so it fails and then calls even(N) again. Your specific version of Prolog likely sees that it is an infinitely recursive predicate and doesn't even try to satisfy it even though it's a valid declarative path , but not a valid procedural path.
If you know that the mode is (+), you can place a cut,
to suppress the unnecessary choice point:
even(0) :- !.
even(N) :- N > 0, N1 is N-1, odd(N1).
odd(N) :- N > 0, N1 is N-1, even(N1).
The above is better than wrapping a query with
once/1 since it allows the Prolog interpreter to
use last call optimization. There is now no more
problem with an extra choice point:
?- even(3).
false.
?- even(4).
true.
But if the mode is not fixed, you have to be more careful
with cuts. Probably write a separate carefully crafted
predicate for each mode.
CLP(FD) itself seems not to help, it cannot avoid the need
to place cuts, but can sometimes avoid the need to code
different variants for different modes.

How to compare lists length Prolog

I'm new at Prolog and i was trying to solve some exercises and I found this one twice_as_long(L1,L2) that succeeds if the list L2 is twice as long as the list L1.
Do NOT compute the lengths of the lists.
twice_as_long([],[]).
true.
?- twice_as_long([a],[1,2]).
true.
?- twice_as_long([a,b],X).
X = [_G328, _G331, _G334, _G337] ;
false
I want some hint please cuz i don't want to compare lengths like what they said .
We can generalize your second example as a rule:
twice_as_long([_],[_,_]).
But we can do better:
twice_as_long([_|T1], [_,_|T2]) :- twice_as_long(T1,T2).
That, with the base case from you first example, will do the job.
With respect to Prolog conventions, given a predicate of the form type_of_relationship(X,Y), it's pretty customary to read it as a declaration of fact along the lines of
X has a type_of_relationship with Y.
So, let's flip the order of the arguments: twice_as_long(X,Y) asserts that X is twice as long as Y.
Given that, and amplifying the answer from #ScottHunter, Let's break things down into simple cases.
First, your example shows a case that should fail as succeeding.
twice_as_long([],[]).
asserts that the empty list is twice as long as itself, something that is manifestly untrue: the empty list is of length zero and twice zero is still..zero. So that case should be discarded.
There is, however, the simplest case possible:
twice_as_long( [_,_] , [_] ) .
an assertion that a list of length 2 is twice as long as a list of length 1.
Then, there is the generic case:
twice_as_long( [_,_|Xs] , [_|Ys] ) :-
twice_as_long(Xs,Ys) .
in which we say that a list of 2 or more items is twice as long as a list of 1 or more items...
IF, the remainder of the first list is twice as long as the remainder of the second list, where the remainders are obtained by removing the first 2 items from the first list and just 1 item from the second list.
That gives us this as the solution:
twice_as_long( [_] , [_,_] ) .
twice_as_long( [_|Xs] , [_,_|Ys] ) :- twice_as_long(Xs,Ys) .
The predicate will succeed when you get to the simple base case, and fail otherwise.

Taking out the 2nd to last element - Prolog

I'm very new to Prolog and am trying to figure out exactly what is happening with this (function?) that takes out the 2nd to last element in a list.
remove([],[]).
remove([X],[X]).
remove([_,X],[X]).
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
I'm familiar with pattern matching, as I've done a little work in SML. The first one is clearly the base case, returning the empty list when we break it down. The second returns the same variable when there is only one left. The third looks as if it returns the last element, disregarding the 2nd to last? As for the inductive case, it will attach the head of the list to the new list if ...... (This is where I get completely lost). Could anyone explain what's happening in this function so I can have a better understanding of the language?
Elaborating on CapelliC's explanation:
remove([],[]).
An empty list is an empty list with the second-to-last element removed.
remove([X],[X]).
A single-element list is itself with the second-to-last element removed.
remove([_,X],[X]).
A two-element list with the second to last element removed is a list of one element consisting of the last element of the two-element list.
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
The second list is the first list with the second element removed, and share the same first element, IF:
The tail of the first list consists of at least two elements, AND
The tail of the second list is the tail of the first list with the second to last element removed
A set of clauses is a predicate, or procedure.
All first three are base cases, and the recursive one copies while there are at least 3 elements in the first list.
I would describe the behaviour like 'removes pre-last element'.
So, how to declaratively read
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
Most important is that you first realize what the :- actually means.
Head :- Body.
It means: Whenever Body holds, we can conclude that also Head holds. Note the rather unintuitive direction of the arrow. It goes right-to-left. And not left-to-right, as often written informally when you conclude something. However, the error points into the direction of what we get "out of it".
To better see this, you can enter Body as a query!
?- Xs = [_,_|_], remove(Xs,Ys).
Xs = [A, B], Ys = [B]
; Xs = [A, B, C], Ys = [A, C]
; ... .
So we get all answers, except those where Xs has less than two elements.
Please note that procedurally, things happen exactly in the other direction - and that is very confusing to beginners. Even more so, since Prolog uses two "non-traditional" features: chronological backtracking, and variables - I mean real variables, meaning all possible terms - not these compile time constructs you know from imperative and functional languages. In those languages variables are holders for runtime values. Concrete values. In Prolog, variables are there at runtime, too. For more to this, see Difference between logic programming and functional programming
There is also another issue, I am not sure you understood. Think of:
?- remove(Xs, [1,2]).
Xs = [1, A, 2]
; false.
What is removed here? Nothing! Quite the contrary, we are adding a further element into the list. For this reason, the name remove/2 is not ideal in Prolog - it reminds us of command oriented programming languages that enforce that some arguments are given and others are computed. You might at first believe that this does not matter much, after all it's only a name. But don't forget that when programming you often do not have the time to think through all of it. So a good relational name might be preferable.
To find one, start with just the types: list_list/2, and then refine list_removed/2 or list__without_2nd_last/2.
Annotated:
remove( [] , [] ) . % removing the 2nd last element from the empty list yields the empty list
remove( [X] , [X] ) . % removing the 2nd last element from a 1-element list yields the 1-element list.
remove( [_,X] , [X] ) . % removing the 2nd last element from a 2-element list yields the tail of the 2-element list
remove( [X|Xs] , [X|Ys] ) :- % for any other case...
Xs = [_,_|_], % * if the tail contains 2 or more elements, the list is 3 elements or more in length
remove(Xs,Ys). % we simply prepend the head of the list to the result and recurse down.
It should be noted that the last clause could re-written a tad more clearly (and a little more succinctly) as:
remove( [X1,X2,X3|Xs] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
remove([X2,X3|Xs],Ys). % we simply prepend the head of the list to the result and recurse down.
Or as
remove( [X1|[X2,X3|Xs]] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
remove([X2,X3|Xs],Ys). % we simply prepend the head of the list to the result and recurse down.

Resources