Prolog tries to find multiple solutions when only one exists - prolog

I've made a basic predicate ascending/1 to check if a list is in ascending order, on https://swish.swi-prolog.org.
ascending([]).
ascending([_]).
ascending([X, Y| T]) :-
X =< Y,
ascending([Y|T]).
It shows the following if I query ?- ascending([1, 2, 4, 6]).:
As in, it tries to find more solutions. Pressing Next, 10, 100 or 1,000 just returns false, which is a mystery in and of itself - true and false at the same time? Maybe that's because of the anonymous _? Have I not defined completely enough? Why is it not just returning true?

Most Prolog systems implement first-argument indexing, which allows avoid creating spurious choice-points. Assuming that and a call with the first argument bound, in the case of your code, the Prolog runtime is able to able to distinguish between the first clause, whose first argument is an atom, and the two other clauses, whose first argument are lists. But not able (in general) to distinguish between the second and third clauses and avoid trying both for a goal where the first argument is a list. This results in the creation of a choice-point. Hence the results your get:
?- ascending([1, 2, 4, 6]).
true ;
false.
But we can improve on your solution. For example:
ascending([]).
ascending([Head| Tail]) :-
ascending(Tail, Head).
ascending([], _).
ascending([Head| Tail], Previous) :-
Previous =< Head,
ascending(Tail, Head).
We will now get:
?- ascending([1, 2, 4, 6]).
true.
?- ascending([1, 2, 4, 6, 1]).
false.

Related

How does backtracking in recursion not cause an infinite loop?

Assume the member/2 predicate is defined as:
member(X,[X|R]).
member(X,[Y|R]) :- member(X,R).
My query is:
member(X, [1, 2, 3]).
Once prolog unifies X with 1, how does prolog get the other possible unifications if I type ;?
Wouldn't Prolog backtrack and then re-read my file containing the definition of member from top to bottom and evaluate member(X,[X|R]). again which would unify X with 1 again?
How about this
Note the following:
The program is read once and then stays in memory, waiting for the user to enter a query (same as for a database scenario)
As it executes it builds a "search tree" in memory
An OR node for every predicate encountered: ANY of the branches (which correspond to clauses of that predicate) must be made TRUE
An AND node for every clause body encountered: all the branches (which correspond to the calls made in the clause body that are seprated by ,) must be made TRUE
The program SUCCEEDS when it can "exit at the bottom of the tree" and
Below any AND node, all the branches are TRUE
Below any OR node, at least one of the branches are TRUE (In Prolog, there is only every exactly ONE "active branch" below an OR node)
The program eventually FAILS if no such tree can be found (which may take some time).
On program success, the tree is kept alive in case the user ask for "more solutions"
If you ask for "more solutions", the tree is re-entered at the bottom and alternative branches are tried.
And:
Variable names are local to a clause
Variable content (which is either a term or a cell with no content if the "variable is unbound" as they say) is always global. If a node deep in the tree "refines" the content of one of its variable, this change is visible at the topmost node of the tree (albeit under another name or part of another term).
The rules you stated are:
member(X, [X | R]).
The pipe operator separates the first element of the list from the rest of the list. So, if list is [1, 2, 3], X = 1, and R = [2, 3].
X is the car of the [X | R] list (i.e. first member).
So in this case, member(1, [1, 2, 3]). is true.
member(X, [Y | R]) :- member(X, R).
This second case covers when the first member of the list is different from X. If this is so, member(X , R) is called and this inspects the cdr of the list (i.e. from second element on).
So, member(1, [1, 2, 3]). doesn't trigger a recursion.
What happens, for instance, when the element is not on the list ?
For brevity, member(1, [2]). is true or false ?
This falls on the second rule, since X = 1 is different from Y = 2.
But then, the cdr of the list is an empty list (i.e. there are no elements beside the first).
So member(1, [2]) :- member(1, [])., and this member(1, []) evaluation is always false.
Prolog's output:
~ $ swipl
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- [user].
|: member(X, [X | L]) :- write('Evaluated first clause with X='), write(X), write('.'), nl.
|: member(X, [Y | L]) :- write('Evaluated second clause with X='), write(X), write(' and Y='), write(Y), write('.'), nl, member(X, L).
|: end_of_file.
% user://1 compiled 0.01 sec, 2 clauses
true.
?- member(1, [1, 2, 3]).
Evaluated first clause with X=1.
true .
?- member(2, [1, 2, 3]).
Evaluated second clause with X=2 and Y=1.
Evaluated first clause with X=2.
true .
?- member(4, [1, 2, 3]).
Evaluated second clause with X=4 and Y=1.
Evaluated second clause with X=4 and Y=2.
Evaluated second clause with X=4 and Y=3.
false.
?- X=1, member(X, [1, 2, 3]).
Evaluated first clause with X=1.
X = 1 .
(omitted warnings).

Prolog Program Not Merging Sorted Lists Correctly

I have a simple program I'm trying to write in Prolog. Essentially, as I learning exercise, I'm trying to write a program that takes two sorted lists as input, and returns the merged list that is also sorted. I have dubbed the predicate "merge2" as to no be confused with the included predicate "merge" that seems to do this already.
I am using recursion. My implementation is below
merge2([],[],[]).
merge2([X],[],[X]).
merge2([],[Y],[Y]).
merge2([X|List1],[Y|List2],[X|List]):- X =< Y,merge2(List1,[Y|List2],List).
merge2([X|List1],[Y|List2],[Y|List]):- merge2([X|List1],List2,List).
When I run this, I get X = [1,2,4,5,3,6] which is obviously incorrect. I've been able to code multiple times and tried to draw out the recursion. To the best of my knowledge, this should be returning the correct result. I'm not sure why the actualy result is so strange.
Thank you.
QuickCheck is your friend. In this case, the property that you want to verify can be expressed using the following predicate:
sorted(L1, L2) :-
sort(L1, S1),
sort(L2, S2),
merge2(S1, S2, L),
sort(L, S),
L == S.
Note that sort/2 is a standard Prolog built-in predicate. Using the QuickCheck implementation provided by Logtalk's lgtunit tool, which you can run using most Prolog systems, we get:
?- lgtunit::quick_check(sorted(+list(integer),+list(integer))).
* quick check test failure (at test 2 after 0 shrinks):
* sorted([0],[0])
false.
I.e. you code fails for L1 = [0] and L2 = [0]:
?- merge2([0], [0], L).
L = [0, 0] ;
L = [0, 0] ;
false.
Tracing this specific query should allow you to quickly find at least one of the bugs in your merge2/4 predicate definition. In most Prolog systems, you can simply type:
?- trace, merge2([0], [0], L).
If you want to keep duplicates in the merged list, you can use the de facto standard predicates msort/2 in the definition of the property:
sorted(L1, L2) :-
sort(L1, S1),
sort(L2, S2),
merge2(S1, S2, L),
msort(L, S),
L == S.
In this case, running QuickCheck again:
?- lgtunit::quick_check(sorted(+list(integer),+list(integer))).
* quick check test failure (at test 3 after 8 shrinks):
* sorted([],[475,768,402])
false.
This failure is more informative if you compare the query with your clauses that handle the case where the first list is empty...
This is done using difference list and since you are learning it uses reveals, AKA spoiler, which are the empty boxes that you have to mouse over to ravel the contents. Note that the reveals don't allow for nice formatting of code. At the end is the final version of the code with nice formatting but not hidden by a reveal so don't peek at the visible code at the very end if you want to try it for yourself.
This answer takes it that you have read my Difference List wiki.
Your basic idea was sound and the basis for this answer using difference list. So obviously the big change is to just change from closed list to open list.
As your code is recursive, the base case can be used to set up the pattern for the rest of the clauses in the predicate.
Your simplest base case is
merge2([],[],[]).
but a predicate using difference list can use various means to represent a difference list with the use of L-H being very common but not one I chose to use. Instead this answer will follow the pattern in the wiki of using two variables, the first for the open list and the second for the hole at the end of the open list.
Try to create the simple base case on your own.
merge2_prime([],[],Hole,Hole).
Next is needed the two base cases when one of the list is empty.
merge2_prime([X],[],Hole0,Hole) :-
Hole0 = [X|Hole].
merge2_prime([],[Y],Hole0,Hole) :-
Hole0 = [Y|Hole].
Then the cases that select an item from one or the other list.
merge2_prime([X|List1],[Y|List2],Hole0,Hole) :-
X =< Y,
Hole0 = [X|Hole1],
merge2_prime(List1,[Y|List2],Hole1,Hole).
merge2_prime(List1,[Y|List2],Hole0,Hole) :-
Hole0 = [Y|Hole1],
merge2_prime(List1,List2,Hole1,Hole).
Lastly a helper predicate is needed so that the query merge2(L1,L2,L3) can be used.
merge2(L1,L2,L3) :-
merge2_prime(L1,L2,Hole0,Hole),
Hole = [],
L3 = Hole0.
If you run the code as listed it will produce multiple answer because of backtracking. A few cuts will solve the problem.
merge2(L1,L2,L3) :-
merge2_prime(L1,L2,Hole0,Hole),
Hole = [],
L3 = Hole0.
merge2_prime([],[],Hole,Hole) :- !.
merge2_prime([X],[],Hole0,Hole) :-
!,
Hole0 = [X|Hole].
merge2_prime([],[Y],Hole0,Hole) :-
!,
Hole0 = [Y|Hole].
merge2_prime([X|List1],[Y|List2],Hole0,Hole) :-
X =< Y,
!,
Hole0 = [X|Hole1],
merge2_prime(List1,[Y|List2],Hole1,Hole).
merge2_prime(List1,[Y|List2],Hole0,Hole) :-
Hole0 = [Y|Hole1],
merge2_prime(List1,List2,Hole1,Hole).
Example run:
?- merge2([1,3,4],[2,5,6],L).
L = [1, 2, 3, 4, 5, 6].
?- merge2([0],[0],L).
L = [0, 0].
I didn't check this with lots of examples as this was just to demonstrate that an answer can be found using difference list.

Prolog: sum the elements of a list

I am very new to prolog and I'm trying to sum the elements of a list.
So far, I have this:
sum([],_,_). %base case
sum([H|T], Y, _X):-
X2 is H + Y,
sum(T,X2,X2).
testing with sum([1,2,3,4], 0, X) results in an error, but I'm not sure what's wrong with this code. Could someone point me in the right direction?
The code you gave is closer to working than you probably think, but it has a couple problems.
For one, Prolog predicates aren't functions, they don't return results like functions in other languages do. Predicates, instead, declare something about what is true. Later you can give prolog queries and it'll try to make them true.
For example, calls to length/2 are true when the left argument is a list, and the right argument is an int with the length of the list:
?- length([1, 2, 3, 4], 4).
true.
?- length([1, 2, 3, 4], X).
X = 4.
?- length(X, 2).
X = [_2300, _2306].
Looking back at your first line:
sum([],_,_). %base case
This says "sum/3 is always true, as long as the first element is an empty list". You can test this:
?- sum([], -20, hello).
true.
That's probably not what you were intending.
I'm not sure how to put the rest of this without just giving away the answer, but look at what this clause is saying:
sum([H|T], Y, _X):-
X2 is H + Y,
sum(T,X2,X2).
"sum([H|T], Y, WhoCaresIllNeverUseThisVariable) is true if we can recur and prove that sum(T, H+Y, H+Y) is true".
Well, one point, that last argument is a little weird, because in both clauses you assign it to an anonymous variable (_ and _X). What you're saying is, "the third argument never matters and should match literally anything the uses throws at it". I don't think that's what you mean to say.
Second point, I don't know if you realize it but, you're actually computing a sum here! While trying to make sum([1, 2, 3, 4], 0, X) true Prolog will traverse the list and add each element to the middle argument, your accumulator. The summing part works! What you're failing to do is extract the sum from this predicate.
Generally in Prolog you "return" results by making them an additional argument. You could look at length/2 this way. Here's a way you might write it yourself:
my_length([], 0).
my_length([_|Rest], Length) :-
my_length(Rest, Length1),
Length is Length1 + 1.
This function "returns" the length of the array by only being true when the second argument of the predicate is the length of the array.

How to check certain elements in a list with anonymous variables

Imagine having a list like L = [1, 4, _, 5, _]
If I would want to check if 4 is a member of this list, I could do this with: member(4, L). This will return True, because there is a 4 in this list. However it returns true with every element I check, using member/2. This, of course, happens, because an anonymous variable can be matched with anything. So it will always return True. I was wondering if there would be a way I can remove all anonymous variables from list L. So a NewList would be [1, 4, 5].
Instead of removing variables from the list and then use member/2 you could also opt to implement your own predicate that describes a member/2-like relation for non-variable elements:
nonvarmember(X,[Y|_]) :-
nonvar(Y), % only try to unify with X if Y is not a variable
X=Y.
nonvarmember(X,[_Y|Ys]) :-
nonvarmember(X,Ys).
Now let's see how this predicate works:
?- nonvarmember(4,[1,4,_,5,_]).
true ;
false.
?- nonvarmember(4,[1,_,_,5,_]).
false.
?- nonvarmember(4,[1,4,_,5,_,Z]).
true ;
false.
However, the first argument still can be a variable:
?- nonvarmember(X,[1,4,_,5,_,Z]).
X = 1 ;
X = 4 ;
X = 5 ;
false.
?- nonvarmember(X,[_,_,_]).
false.
But be aware that it does not matter if you remove the variable elements from the list first and subsequently use member/2 or if you use nonvarmember/2, you run into the following problem: List-elements that are instantiated after you check for membership are not accounted for and hence might lead to unsound answers. The following example illustrates the problem:
?- A=4, nonvarmember(4,[A,B,C]).
A = 4 ;
false.
?- nonvarmember(4,[A,B,C]), A=4.
false.
In order to check if certain items are in a list that contains anonymous variables, you'd first need to (temporarily) remove all anonymous variables from that list. To do so you could use the built-in predicate subtract/3 and var/1.
subtract/3: the first element being the list you want to check, the second element being a list containing elements you want to remove from the list and the third element being the resulting list.
var/1: contains only one element (X) and returns True if X is an unbound variable.
In this case we want to subtract every element (X) that is returning True when var(X). In code, this is written as var(_).
Now we simply fill in the subtract/3 predicate like this: subtract(L, [var(_)], NewList).
NewList now only stores bound variables and member/2 will now work as intented.
In case of Swi-Prolog (at least) you can use include/3 and exclude/3 predicates to filter lists. You can use these predicates together with var/1 and nonvar/1, to remove variables from list.
In your particular case, checking whether 4 belongs to the list [1, 4, _, 5, _] could be done as follows:
L1 = [1, 4, _, 5, _],
exclude(var, L1, L2),
member(4, L2).

How to get a list of possible predicate values

Lets I have a predicate p/1 defined, for example, as follows:
p(2).
p(3).
p(5).
p(7).
How can I define a predicate p_list/1 which will be true for a list of all possible values of p/1 (in above case - [2, 3, 5, 7]) in the backtracking order?
Simple enumeration of the values is not acceptable because it makes maintenance more difficult. Moreover values, can be defined implicitly.
You can use bagof(X, p(X), L) which gives you L = [2,3,5,7].
What do you mean by "defined implicitly" ? Can you give an example.
maplist/2 works well for check, while findall/3 it's the basic list constructor in Prolog
Try
?- findall(X, p(X), L), maplist(p, L).

Resources