Commutativity of Cut Operator in Prolog - prolog

I'm currently studying Prolog, and in one of the notes I'm reading an example is given of how to use the cut operator correctly. Consider the following function to remove all elements of a particular value from a list.
rm(_,[],[]).
rm(A,[A|L],R) :- rm(A,L,R).
rm(A,[B|L],[B|R]) :- rm(A,L,R).
Due to backtracking, this is not a correct definition of the function, and the function will return all sublists of the list obtained from removing some elements of a particular value, but not necessarily all of them. The notes I'm reading say that a correct way to fix this is to replace the second line by the line
rm(A,[A|L],R) :- !, rm(A,L,R)
But that replacing the line by
rm(A,[A|L],R) :- rm(A,L,R), !
is not correct. I'm not sure why the second example is an incorrect way to fix the function. In swipl, replacing the second term by these fixes seems to always return the same answer on the test cases I consider. What am I missing here?

Your example is a perfect example to illustrate why using the cut here is never a good idea.
Using rm(A,[A|L],R) :- !, rm(A,L,R). makes only sense if both the first and second argument are sufficiently instantiated. But if they are insufficiently instantiated, you get an incomplete answer like:
?- rm(X, [a], R).
X = a, R = []. % incomplete
This clearly misses an answer, as it constrains X to be a only. But if X is anything else, we get a different result, namely:
?- X = b, rm(X,[a],R).
R = [a].
Using the cut at the end as in rm(A,[A|L],R) :- rm(A,L,R), !. is even worse: First, all our assumptions so far must hold, and then additionally the third argument must not be instantiated. Otherwise we get additional incorrect solutions.
?- rm(a,[a],R).
R = [].
?- rm(a,[a],[a]).
true, unexpected. % incorrect
Just recall what we are asking here:
User: When removing a from the list [a] what do we get?
Prolog: Nothing, nil, nada.
User: But can't I have instead of nothing just [a]? Please!
Prolog: OK, I give in.
That's not the way you want to implement an accounting system.
So both uses of cuts are bad. But the second one is clearly worse for it has many more preconditions to remember and is also inefficient.
On the other hand there are some cases where you can use these predicates. But typically it is quite difficult to remember when this is safe. Thus such cuts are a permanent source of errors.
Is there any hope to get rid of all this fine print? Fortunately, there is a way out using if_/3 from library(reif) for SICStus|SWI. Download it and say:
:- use_module(reif).
rm(_,[],[]).
rm(A,[X|Xs], Ys0) :-
if_(A = X, Ys0 = Ys, Ys0 = [X|Ys]),
rm(A, Xs, Ys).
This program is comparably efficient but does not have any of the aforementioned defects:
?- rm(X, [a], R).
X = a, R = []
; R = [a], dif(X, a).
Note the second new answer! It says that for all X that are different to a, the list remains unchanged.

Related

Merging two ordered lists ProLog

Hey so this is my code so far. I am only a begginer in prolog but i need it for school
firstElement([_|_], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2, merge([Elem1] , List1, [Elem2|List2]);
merge([], [Elem2], List2).
merge([Head|Tail], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2,!, add(Elem1,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], List1, [Elem2|List2]);
add(Elem2,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], [Elem1|List1], List2).
merge([Head|Tail], [], [Elem2|List2]):-
add(Elem2,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [Elem1|List1], []):-
add(Elem1,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [], []).
add(X,[],[X]).
add(X,[Y|Tail],[Y|Tail1]):-
add(X,Tail,Tail1).
I found out that everytime it gets out of a merge it keeps forgetting the last number so it gets back to nothing in the end.
I think you’ve gotten very mixed up here with your code. A complete solution can be had without helpers and with only a few clauses.
First let us discuss the two base cases involving empty lists:
merge(X, [], X).
merge([], X, X).
You don’t quite have these, but I see some sort of recognition that you need to handle empty lists specially in your second and third clauses, but I think you got confused and overcomplicated them. There’s really three scenarios covered by these two clauses. The case where both lists are empty is a freebie covered by both of them, but since that case would work out to merge([], [], []), it’s covered. The big idea here is that if you exhaust either list, because they were sorted, what you have left in the other list is your result. Think about it.
This leaves the interesting case, which is one where we have some items in both lists. Essentially what you want to do is select the smaller of the two, and then recur on the entire other list and the remainder of the one you selected the smaller value from. This is one clause for that:
merge([L|Ls], [R|Rs], [L|Merged]) :-
L #< R,
merge(Ls, [R|Rs], Merged).
Here’s what you should note:
The “result” has L prepended to the recursively constructed remainder.
The recursive call to merge rebuilds the entire second list, using [R|Rs].
It should be possible to build the other clause by looking at this.
As an intermediate Prolog user, I would be naturally a bit suspicious of using two clauses to do this work, because it’s going to create unnecessary choice points. As a beginner, you will be tempted to erase those choice points using cuts, which will go badly for you. A more intermediate approach would be to subsume both of the necessary clauses into one using a conditional operator:
merge([L|Ls], [R|Rs], [N|Ns]) :-
( L #< R ->
N = L, merge(Ls, [R|Rs], Ns)
; —- other case goes here
).
An expert would probably build it using if_/3 instead:
#<(X,Y,true) :- X #< Y.
#<(X,Y,false) :- X #>= Y.
merge([L|Ls], [R|Rs], [N|Ns]) :-
if_(#<(L,R),
(N = L, merge(Ls, [R|Rs], Ns)),
( -- other case here )).
Anyway, I hope this helps illustrate the situation.

Prolog and List Unification

I'm trying to further my understanding of Prolog, and how it handles unification. In this case, how it handles unification with lists.
This is my knowledgebase;
member(X, [X|_]).
member(X, [_|T]):- member(X, T).
If I'm understanding the process correctly. If member(X, [X|_]) is not true, then it moves into the recursive rule, and if X is in list T, then [_|T] is unified with T.
So what happens to the anonymous variable in my recursive predicate? Does it get discarded? I'm having difficulty understanding the exact unification process with lists, as [_|T] is two variables, rather than one. I'm just trying to figure out how the unification process works precisely with lists.
Assume that _ is Y
member(X, [Y|T]):- member(X, T).
Then this is True regardless Y. Now you are "returning" member(X, T). In other words, you are discarding Y and "returning" member(X, T).
_ means, whatever it is, ignore that variable.
The _ is just like any other variable, except that each one you see is
treated as a different variable and Prolog won't show you what it
unifies with. There's no special behavior there; if it confuses you
about the behavior, just invent a completely new variable and put it
in there to see what it does.
In your case, your function check if a given element exists on a list, so, you take first element of the list, check if is equal, if not, you discard that element and moves on.
I think your primary question of how lists are represented as variables has been adequately answered, but I sense there are some other aspects to Prolog that need clarification.
To understand Prolog predicates and clauses, it's a good idea not to think of them as "functions" that "return" things, even metaphorically. It can lead you down the dark path of imperative thinking in Prolog. :)
In considering the predicate:
(1) member(X, [X|_]).
(2) member(X, [_|T]) :- member(X, T).
Think of member/2 as a relation which describes when element X is a member of the list L, and the clauses are the rules for determining when it is true.
I'll assume that you already know about how lists are represented in Prolog based upon other answers (e.g., Will Ness' detailed answer).
The first clause says:
(1) X is a member of [X|_] regardless of what the tail of the list [X|_] is
In that notation, the variable _ represents the tail of list [X|_] and X represents the first element of that list. It's trivially true that X is a member of this list, so member(X, [X|_]). is a fact. It's true regardless of what the tail of the list is, so we just use _ (an anonymous variable) since this rule doesn't need the information. Prolog doesn't technically "throw the value away" but the programmer throws it away because the programmer isn't using it. If we had, instead, said, member(X, [X|T]). that would work fine, but we're not using T. Prolog might instantiate it, but it wouldn't be used. It's like assigning x = 3 in C but not using it's value. In this case, Prolog will indicate a warning about a "singleton" variable. Watch for those, because it often means you misspelled something or forgot something. :)
The next rule is recursive. It says:
(2) X is a member of list [_|T] if X is a member of the tail (T) of that list, regardless of what the first element of the list is
Here we're considering the less trivial case where the first element in the list may not be a match to X, so the truth value of member(X, L) depends, in this rule, upon the truth value of member(X, T) where T is the tail (everything but the first element) of L. The rule does not unify member(X, [_|T]) with member(X, T), so it does not unify T with [_|T] as you might suppose. The :- operator defines a rule or implication (note the if in the rule description). [N.B., If you were to unify these terms, it would be done with with the unification operator, =/2: member(X, [_|T]) = member(X, T)].
On the recursive query member(X, T), Prolog goes back to the top, the first rule, and attempts to unify the first argument X with the head of the second argument (which is the original list minus its first element, or head) and, if it doesn't match, goes to rule #2 again, continually checking the tail as well, until it can unify. If it gets to the point where the tail is empty ([]) and hasn't been able to unify X with any elements, the predicate fails because there are no facts or rules that match member(X, []). However, if it does unify X with an element, it succeeds (it does not "return a value* in the sense that a function would in other languages) and reveals the values of any variables it instantiated in the arguments in the process, or simply will succeed if all the arguments passed are already instantiated. If there are more rules to check after succeeding (there was what's called a choice point), it will (if you tell it to) go back and check for more solutions and, if it finds them, display them as well. Or display no or false if there are no more.
Looking at an example query, is b a member of [a,b,c]?
member(b, [a,b,c]).
Prolog will first try to unify the query with a fact or the head of a predicate. The first one it finds is:
member(X, [X|_]).
In attempting to unify, X = b, but [a,b,c] (or, [a|[b,c]] in the head-tail notation) doesn't unify with [b|_](note the head elementsaandb` mismatch). Prolog then moves on to the next clause:
member(X, [_|T]) :- member(X, T).
In unifying member(b, [a,b,c]) with the head, it comes up with:
member(b, [_|[b,c]]) :- member(b, [b,c]).
It now has the recursive query to chase down: member(b, [b,c]). Since it's a new query, it starts at the top again and attempts to unify this with member(X, [X|_]). Now, it's successful, because member(b, [b,c]) (or, member(b, [b|[c]])) matches this pattern: member(b, [b|_]).
Therefore, the member(b, [a,b,c]). succeeds and Prolog will return "true". However, it's not done yet because it left what's called a choice point. Even though it matched member(b, [b,c]) with the first clause, it will still want to go back and find more cases that make it succeed, and there's still another clause to pursue. So, Prolog will go back and try member(b, [b,c]) against the second clause, matching member(b, [b|[c]]) to member(b, [_|[c]]) and doing another recursive query, member(b, [c]) and so on until it ultimately fails to find another solution. This is why the query looks something like this:
| ?- member(b, [a,b,c]).
true ? ;
no
| ?-
It first succeeds, but then we ask for more (with ;) and it then fails (no). This confuses some Prolog beginners, but it's because we've asked Prolog to get another solution, and it said there are none.
Because Prolog continues to try to find solutions (upon request), you can also use a variable in the query:
member(E, [a,b,c]).
This query runs the same way as the prior example, but now I have a variable as the first argument. Prolog will successfully match this to the first clause: member(E, [a,b,c]) unifies with member(X, [X|_]) via E = a. So you'll see something like:
| ?- member(E, [a,b,c]).
E = a ?
If we now ask for more solutions with ;, Prolog goes back and attempts the second clause, unifying member(E, [a|[b,c]]) with member(X, [_|T]) yielding _ = a (which is ignored in the predicate) and T = [b,c]. It then recursively queries, member(E, [b,c]) and, since it's a new query, goes back to the top and matches member(X, [X|_]) again, this time with E = b. So we see:
| ?- member(E, [a,b,c]).
E = a ? ;
E = b ?
And so on. member(E, [a,b,c]) will find all the values of E which make member(E, [a,b,c]) true and then finally fail after exhausting all the elements of [a,b,c]).
[A|B] represents a list where A is the Head element and B is the whole rest list.
So to explain you the algorithm shortly:
Clause: If X is the first element of the list the predicate succeeds.
Clause: If that's not the case, we try to find X in the tail of the list. Therefore, we call member recursively but instead of passing the whole list we now pass the list EXCEPT the head element. In other words, we walk through the list step by step always looking at the head element first. If that is not our element, we dig further.
Think of the anonymous variable _ just as a variable you do not need later. The algorithm would also work, if you replaced _ by a capital letter, however it would give you a warning that you named a variable that you never use.
A list is just a compound term with the '.' functor:
1 ?- [_|T] = .(_,T).
true.
2 ?- [_|T] =.. X.
X = ['.', _G2393, T].
The usual process of structural unification of compound terms apply:
3 ?- [A|T] = .(B,R).
A = B,
T = R.
[A|T] is really .(A,T) so the functors (.) and the arities (both terms are binary, of arity 2) match, so the respective constituents are matched as well.
Yes, the anonymous variable _ is ignored for the purposes of reporting the unification results. Otherwise it is just a fresh uniquely named variable.
it moves into the recursive rule, and if X is in list T, then [_|T] is unified with T.
Not quite. The unification happens before the "moving on", as part of the clause selection. To unify a list L with [_|T] is to select its "tail" and have T referring to it. E.g.
4 ?- L = [1,2,3], L = [_|T].
L = [1, 2, 3],
T = [2, 3].
(_ is 1 but is not reported).

Prolog no_duplicate function

I'm trying to write a simple procedure that checks if a list has any duplicates. This is what I have tried so far:
% returns true if the list has no duplicate items.
no_duplicates([X|XS]) :- member(X,XS) -> false ; no_duplicates(XS).
no_duplicates([]) :- true.
If I try no_duplicates([1,2,3,3]). It says true. Why is this? I'm probably misunderstanding Prolog here, but any help is appreciated.
To answer your questions: your solution actually fails as expected for no_duplicates([1,2,3,3]). So there is no problem.
Now take the queries:
?- A = 1, no_duplicates([A, 2]).
A = 1.
?- no_duplicates([A, 2]), A = 1.
They both mean the same, so we should expect that Prolog will produce the same answer. (To be more precise we expect the same ignoring errors and non-termination).
However, four proposed solutions differ! And the one that does not, differs for:
?- A = 2, no_duplicates([A, 2]).
false.
?- no_duplicates([A, 2]), A = 2.
Note that it is always the second query that makes troubles. To solve this problem we need a good answer for no_duplicates([A, 2]). It cannot be false, since there are some values for A to make it true. Like A = 1. Nor can it be true, since some values do not fit, like A = 2.
Another possibility would be to issue an instantiation_error in this case. Meaning: I have not enough information so I better stop than mess around with potentially incorrect information.
Ideally, we get one answer that covers all possible solutions. This answer is dif(A, 2) which means that all A that are different to 2 are solutions.
dif/2 is one of the oldest built-in predicates, already Prolog 0 did possess it. Unfortunately, later developments discarded it in Prolog I and thus Edinburgh Prolog and thus ISO Prolog.
However, current systems including SICStus, YAP, SWI all offer it. And there is a safe way to approximate dif/2 safely in ISO-Prolog
no_duplicates(Xs) :-
all_different(Xs). % the common name
all_different([]).
all_different([X|Xs]) :-
maplist(dif(X),Xs).
all_different(Xs).
See: prolog-dif
Here's yet another approach, which works because sort/2 removes duplicates:
no_duplicates(L) :-
length(L, N),
sort(L, LS),
length(LS, N).
I'd go at the problem more descriptively:
no_duplicates( [] ) . % the empty list is unique
no_duplicates( [X|Xs] ) :- % a list of length 1+ is unique
\+ member(X,Xs) , % - if its head is not found in the tail,
no_duplicates(Xs) % - and its tail is itself unique.
. %
Thinking on this, since this is a somewhat expensive operation — O(n2)? — it might be more efficient to use sort/2 and take advantage of the fact that it produces an ordered set, removing duplicates. You could say something like
no_duplicates( L ) :-
sort(L,R) , % sort the source list, removing duplicates
length(L,N) , % determine the length of the source list
length(R,N) . % check that against the result list
Or you could use msort/3 (which doesn't remove duplicates), might be a bit faster, too:
no_duplicates( L ) :-
msort(L,R), % order the list
\+ append(_,[X,X|_],R) % see if we can find two consecutive identical members
.
Duplicates in a list are same elements not at the same place in the list, so no_duplicates can be written :
no_duplicates(L) :-
\+((nth0(Id1, L, V), nth0(Id2, L, V), Id1 \= Id2)).
Jay already noted that your code is working. An alternative, slightly less verbose
no_duplicates(L) :- \+ (append(_, [X|XS], L), memberchk(X, XS)).

Predicate that succeeds if two or more results are returned

How to implement rule1 that succeeds iff rule2 returns two or more results?
rule1(X) :-
rule2(X, _).
How can I count the results, and then set a minimum for when to succeed?
How can I count the results, and then set a minimum for when it's true?
It is not clear what you mean by results. So I will make some guesses. A result might be:
A solution. For example, the goal member(X,[1,2,1]) has two solutions. Not three. In this case consider using either setof/3 or a similar predicate. In any case, you should first understand setof/3 before addressing the problem you have.
An answer. The goal member(X,[1,2,1]) has three answers. The goal member(X,[Y,Z]) has two answers, but infinitely many solutions.
So if you want to ensure that there are at least a certain number of answers, define:
at_least(Goal, N) :-
\+ \+ call_nth(Goal, N).
with call_nth/2 defined in another SO-answer.
Note that the other SO-answers are not correct: They either do not terminate or produce unexpected instantiations.
you can use library(aggregate) to count solutions
:- use_module(library(aggregate)).
% it's useful to declare this for modularization
:- meta_predicate at_least(0, +).
at_least(Predicate, Minimum) :-
aggregate_all(count, Predicate, N),
N >= Minimum.
example:
?- at_least(member(_,[1,2,3]),3).
true.
?- at_least(member(_,[1,2,3]),4).
false.
edit here is a more efficient way, using SWI-Prolog facilities for global variables
at_least(P, N) :-
nb_setval(at_least, 0),
P,
nb_getval(at_least, C),
S is C + 1,
( S >= N, ! ; nb_setval(at_least, S), fail ).
with this definition, P is called just N times. (I introduce a service predicate m/2 that displays what it returns)
m(X, L) :- member(X, L), writeln(x:X).
?- at_least(m(X,[1,2,3]),2).
x:1
x:2
X = 2.
edit accounting for #false comment, I tried
?- call_nth(m(X,[1,2,3]),2).
x:1
x:2
X = 2 ;
x:3
false.
with call_nth from here.
From the practical point of view, I think nb_setval (vs nb_setarg) suffers the usual tradeoffs between global and local variables. I.e. for some task could be handly to know what's the limit hit to accept the condition. If this is not required, nb_setarg it's more clean.
Bottom line: the better way to do would clearly be using call_nth, with the 'trick' of double negation solving the undue variable instantiation.

Simple Prolog delete from list

(This is NOT a coursework question. Just my own personal learning.)
I'm trying to do an exercise in Prolog to delete elements from a list. Here's my code :
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H==X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :- deleteall(T,X,Result).
When I test it, I first get a good answer (ie. with all the Xs removed.) But then the backtracking offers me all the other variants of the list with some or none of the instances of X removed.
Why should this be? Why do cases where H==X ever fall through to the last clause?
When you are using (==)/2 for comparison you would need the opposite in the third rule, i.e. (\==)/2. On the other hand, such a definition is no longer a pure relation. To see this, consider deleteall([X],Y,Zs), X = Y.
For a pure relation we need (=)/2 and dif/2. Many Prologs like SWI, YAP, B, SICStus offer dif/2.
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H=X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :-
dif(H,X),
deleteall(T,X,Result).
Look at the answers for deleteall([X,Y],Z,Xs)!
Edit (after four years):
More efficiently, but in the same pure vein, this can be written using if_/3 and (=)/3:
deleteall([], _X, []).
deleteall([E|Es], X, Ys0) :-
if_( E = X, Ys0 = Ys, Ys0 = [E|Ys] ),
deleteall(Es, X, Ys).
The last clause says that when removing X from a list, the head element may stay (independently of its value). Prolog may use this clause at any time it sees fit, independently of whether the condition in the preceding clause is true or not backtrack into this clause if another clause fails, or if you direct it to do so (e.g. by issuing ; in the top-level to get the next solution). If you add a condition that the head element may not equal X, it should work.
Edit: Removed the incorrect assertion I originally opened with.

Resources