My lecturer gave us this sample program to look at the code, while I understood the recursive function on a whole the was this one line I couldn't quite grasp the meaning of
all_different([H | T]) :- member(H, T), !, fail.
extracted from the recursive function:
all_different([H | T]) :- member(H, T), !, fail.
all_different([_ | T]) :- all_different(T).
all_different([_]).
all I understood about it is that it splits a list into a Head H and a Tail T and checks if H is contained in T...My question is, what is it that "!" and "fail" do?
These things are pretty fundamental to Prolog.
fail is essential. It forces Prolog to consider the current branch a failure and initiates backtracking.
The ! is called "the cut." It commits Prolog to the current branch. Or, it prunes the trail of choice points under the current rule.
Taken in conjunction, in Prolog-ese, this says "If the head of the list is present in the tail of the list, there is no need to look for any additional answers, and fail." Thus, if any element of the list is present in the remainder of the list, you'll get an immediate failure with no chance of backtracking. This isn't actually all that dire, it just means that Prolog won't waste any more time trying to figure out if the list is "all_different." Backtracking will resume at the call site normally.
It's important that these go in this order. If you tried to cut after the fail, you'd never make it to the cut, because backtracking would already have begun. If you omit the cut, the predicate will return true if there is any sublist of the list which satisfies the property. This is guaranteed to be the case for any non-empty list by the last clause, which asserts that a list with one element satisfies the property. If you omit the fail, you're just going to get one success for each element of the list that is in a sublist, plus one for the tail. I encourage you to try playing around with the predicate, making these changes and seeing the effects, because it will go a long way to illustrating the purpose of the cut and fail.
Related
I have produced the following code.
list_reverse([],[]).
list_reverse([X],[X]).
list_reverse(Ls,[R|Rs]) :-
last_elem(Ls,R),
without_last_elem(Ls,Next),
list_reverse(Next,Rs).
last_elem([E],E).
last_elem([_|Xs],E) :-
last_elem(Xs,E).
without_last_elem([X,_|[]],[X|[]]).
without_last_elem([X|T0],[X|T1]) :-
without_last_elem(T0,T1).
Swipl:
?- list_reverse([1,2,3],X).
X = [3, 2, 1] ;
false.
This is exactly what I want.
However if I go in the opposite direction I get success, followed by non-termination.
?- list_reverse(X,[1,2,3]).
X = [3, 2, 1] ;
C-c C-cAction (h for help) ? a
abort
% Execution Aborted
What I am struggling to understand is why I first get a correct solution for X. Is my program correct or not?
I am not worried about reversing a list as much as I am about this pattern of getting a correct solution followed by non-termination. It is a pattern I have already come across a few times.
I am [worried] about this pattern of getting a correct solution followed by non-termination.
This is due to the very specific notion of (universal) termination in Prolog. In other programming languages termination is a much simpler beast (still an undecidable beast nevertheless). If, say, a function returns then it terminates (for that case). But in Prolog, producing an answer is not the end as there might be further solutions or just an unproductive loop. In fact, it's best not to consider your query ?- list_reverse(X,[1,2,3]). but rather the following instead.
?- list_reverse(X,[1,2,3]), false.
In this manner all distracting answers are turned off. The only purpose of this query is now either to show termination or non-termination.
After that,
you can either try to follow Prolog's precise execution path but that is as insightful as staring into a car's gearbox when you are lost (the gears caused you to move into the place where you are lost thus they are somehow the cause...). Or, you take a step back, and consider related program fragments (called slices) that share certain properties with your original program. For termination, a failure-slice helps you to better understand what is at stake. In your case consider:
list_reverse([],[]) :- false.
list_reverse([X],[X]) :- false.
list_reverse(Ls,[R|Rs]) :-
last_elem(Ls,R), false,
without_last_elem(Ls,Next),
list_reverse(Next,Rs).
last_elem([E],E) :- false.
last_elem([_|Xs],E) :-
last_elem(Xs,E), false.
?- list_reverse(X,[1,2,3]), false.
Since this failure slice does not terminate, also your original program doesn't terminate! And, it is much easier to reason here in this smaller fragment. If you want to fix the problem, you need to modify something in the visible part. Otherwise you will keep being stuck in a loop.
Note that none of the facts is part of the loop. Thus they are irrelevant for non-termination.
Also note that in list_reverse/2 the variable Rs is never used in the visible part. Thus Rs has no influence on termination! Please note that this is a proof of that property already. Does this mean that the second argument of list_reverse/2 has no influence on termination? What do you think?
The last_elem/2 can keep constructing larger lists, that all should be rejected. But you thus get stuck in an infinite loop.
We can make a function that works with accumulator, and iterates over both the two lists concurrently. That means that once the left or right list is exhausted, no more recursive calls will be made:
reverse(L1, L2) :-
reverse(L1, [], L2, L2).
reverse([], L, L, []).
reverse([H|T], L1, R, [_|T2]) :-
reverse(T, [H|L1], R, T2).
Here the [H|T] and [_|T2] pattern thus both pop the first item of the list, and we only match if both lists are exhausted.
intersection([],L1,L2,L3).
intersection([H|T],L2,L3,[H|L4]):-member(H,L2),intersection(T,L3,L3,L4).
member(H,[H|T]).
member(X,[H|T]):-member(X,T).
This code makes the third list from the first and second list.
last([U],U).
last([_|L3],U) :- last(L3,U).
This piece of code looks for the last item in the list.
My problem is that I can’t figure out how to make these two pieces of code fit into one. That is, the program should find duplicate elements in the first and second list and display them in the third, and from the third list, display the last element multiplied by 3.
The main problem is intersection/4. I assume you wanted to write a deterministic predicate intersection/3 the first two arguments of which are fully instantiated at call time and the last argument of which is an output argument. By deterministic, I mean that intersection/3 should succeed exactly once without leftover choice points. The SWI-Prolog documentation contains a useful overview of determinism and mode declarations (although it does not enforce them).
It is useful to begin by writing a declarative specification of the predicate following the inductive definition of lists:
The intersection of [] and Ys is [].
The intersection of [A|Xs] and Ys is A prepended to the intersection of Xs and Ys if A is a member of Ys.
The intersection of [A|Xs] and Ys is the intersection of Xs and Ys if A is not a member of Ys.
The simplest translation of this specification into standard Prolog is:
intersection([],_,[]).
intersection([A|Xs],Ys,[A|Zs]) :-
member(A,Ys),
intersection(Xs,Ys,Zs).
intersection([A|Xs],Ys,Zs) :-
\+ member(A,Ys),
intersection(Xs,Zs).
If the first call to member/2 succeeds the second should fail. In order to avoid backtracking, unifying the current goal with the head of the second clause, and performing a redundant call to member/2, we place a cut after the occurrence of member/2 in the second clause.
intersection([],_,[]).
intersection([A|Xs],Ys,[A|Zs]) :-
member(A,Ys),
!,
intersection(Xs,Ys,Zs).
intersection([_|Xs],Ys,Zs) :-
intersection(Xs,Ys).
If the current goal unifies with the head of the first clause, it will not unify with the heads of later clauses. In order to prevent spurious backtracking, we place a cut in the (empty) body of the first clause. Whether this cut is necessary depends on your choice of Prolog implementation.
intersection([],_,[]) :-
!.
intersection([A|Xs],Ys,[A|Zs]) :-
member(A,Ys),
!,
intersection(Xs,Ys,Zs).
intersection([_|Xs],Ys,Zs) :-
intersection(Xs,Ys).
We are only interested in checking membership in the second list. Thus, we can replace the occurrence of member/2 with the semideterministic predicate memberchk/2. Here, semideterministic means that memberchk/2 succeeds or fails exactly once without leftover choice points.
intersection([],_,[]).
!.
intersection([A|Xs],Ys,[A|Zs]) :-
memberchk(A,Ys),
!,
intersection(Xs,Ys,Zs).
intersection([_|Xs],Ys,Zs) :-
intersection(Xs,Ys).
This implementation of intersection/3 is nearly identical to the implementation found in the SWI-Prolog library lists.pl. You can combine this predicate with an implementation of last/2 in order to complete your program. For example:
last_duplicate_tripled(Xs,Ys,N) :-
intersection(Xs,Ys,Zs),
last(Zs,M),
N is M * 3.
From here, I recommend doing the following:
Implement intersection/3 using metalogical predicates like findall/3.
Read #false's answer to this question.
Read #repeat's answer to this question.
They are doing something much more interesting and sophisticated than I attempted in this answer.
I am attempting to remove unique elements from a list in Prolog.
Output should look something like:
?- rem_Uniq([3,3,1,7,a,c,c],D).
D = [3, c].
Here is my current code.
rem_Uniq(L1,L2).
rem_Uniq([L1|RL1], [L1|D]) :-
member(L1,RL1),
rem_Uniq(RL1,D).
rem_Uniq([L1|RL1], D) :-
remove(L1[L1|RL1], O),
rem_Uniq(O, D).
Currently it just returns true no matter what I do (whether I enter I list containing unique variables or not).
Anyone have any ideas or suggestions on what I am doing wrong?
D is the set of elements of the list which appears only one time.
In Prolog "an element which appears only one time in a list" can be translate by
select(X, L, L_X),
\+member(X, L_X)
In Prolog exist predicates that collect element with a certain property setof/3 and bagof/3.
bagof collect all the elements, setof keeps only one element.
So you can write
rem_uniq(In, Out) :-
setof(X, In_X^(select(X, In, In_X),\+member(X, In_X)), Out).
[EDIT]
Now we want only elements that are duplicated in a list. If I remove one of these elements of the list, it will remain other elements of the same value in the list so it can be translated in Prolog by
select(X, In, In_X),
member(X, In_X)
(we say that select(X, In, In_X),member(X, In_X) succeed).
Now the code can be written
rem_uniq(In, Out) :-
setof(X, In_X^(select(X, In, In_X),member(X, In_X)), Out).
For example
?- rem_uniq([3,3,1,7,a,c,c],D).
D = [3,c].
Note that setof will fail if there no elements available
?- rem_uniq([3,1,7,a,c],D).
false.
Well, your first problem is your first clause:
rem_Uniq(L1,L2).
This literally says "Any two things are rem_Uniq to each other." This is what's giving rise to always getting true with no unifications. You probably meant this:
rem_Uniq([], []).
Your second problem is that this is not valid syntax:
remove(L1[L1|RL1], O),
Specifically, L1[L1|RL1], I am unclear what you meant there. I think you meant this delete(L1, [L1|RL1], O).
Now, algorithmically, I think you're a little confused. In clause #2, you prepend L1 to D in the result, which is to say, after knowing that L1 is present in RL1 and using the recursive call to remove it from D. But then in clause #3, you just remove it from [L1|RL1] to make O, which you then remove uniques from.
Each clause of a recursive predicate should represent a case you have to worry about. I don't really see what these clauses mean. The first one should be, in case where the list is empty. The second one should be the case where the list is not empty. What you seem to be trying to do here is something like, in the case where the list is not empty and contains the head element, and the case where it is not empty and does not contain the head element, but the distinction between having or not having that element is (or ought to be) meaningless to your library routine. In other words, delete/3 in one non-empty recursive case should be totally sufficient for this problem:
rem_uniq([], []).
rem_uniq([X|Xs], [X|UniqueXs]) :-
delete(X, Xs, XsWithoutX),
rem_uniq(XsWithoutX, UniqueXs).
So, I think you have a little confusion about when and why you should have multiple clauses, and I think your choice of variable names may have made life harder on yourself. But that's just my guess.
Hope this helps!
I am learning Prolog myself and recently came across a piece of notes:-
Example: nth/3
for example, to find the nth element of a list we could use
nth([X|_],0,X).
nth([_|L],N,X) :- N1 is N - 1, nth(L,N1,X).
the 0th element of a list is the head of the list (first clause), otherwise
we take the n-1th element of the tail of the list (second clause).
once we have found the nth element, we can’t find any more by backtracking.
nth([X|_],0,X).
nth([_|L],N,X) :- N1 is N - 1, !, nth(L,N1,X).
adding a cut makes this clear and may be necessary for tail recursion
optimisation.
However, when I use the trace function in Prolog, I found out that the calling sequences of these 2 pieces of codes are exactly the same.
Should I put the ! mark as follows instead?
nth([X|_],0,X) :- !.
nth([_|L],N,X) :- N1 is N - 1, nth(L,N1,X).
The cut in the second clause is redundant as there are no more clauses and the goal before it (the is/2 call) is deterministic. I also don't think that the cut plays any role on tail recursion optimization (which basically requires that you recursive call be the last goal in the clause body).
However, before worrying about cut placement, you should check what happens if you call the nth/3 predicate in a mode other than nth(+,+,-). For example, what happens in mode nth(+,+,+), i.e. when you call the predicate with all arguments instantiated, but the element is not in the list? Hint: moving the cut to the first clause will not solve the problem.
Currently playing around in Prolog... I'm having trouble groking the count list rule. I haven't been able to find a good explanation anywhere. Can someone give me a break down of it at each recursion?
count(0, []).
count(Count, [Head|Tail]) :-
count(TailCount, Tail),
Count is TailCount + 1.
One place says that it is recursive (which makes sense to me) and another that says it isn't.
The procedure it's recursive, but not tail recursive. Writing tail recursive procedures is an optimization that allows the system to transform recursion into iteration, avoiding useless stack usage for deterministics computations (like the one we are speaking of).
In this case (that BTW it's the same of the builtin length/2, just with arguments swapped), we can use an accumulator, and rewrite the procedure in this way:
count(C, L) :- count(0, C, L).
count(Total, Total, []).
count(SoFar, Count, [_Head|Tail]) :-
Count1 is SoFar + 1,
count(Count1, Count, Tail).
Some system older required a cut before the recursive call, to make the optimization effective:
...,
!, count(Count1, Count, Tail).
The definition of the inference rule is recursive.
This program tries to count the quantity of elements inside the list.
count(0, []). This is an axiom, a fact, something that its true because you said so. Here you are stating that every empty list has a count of zero.
count(Count, [Head|Tail]) :-
count(TailCount, Tail),
Count is TailCount + 1.
This is an inference rule, that it a rule that dictates that the left part of :- is true if the right part is true. This inference rule also uses pattern matching, wicth matchs non empty lists ([Head|Tail]).
Specifically, the count rule says that the Count variable of a non empty list is the count of the Tail part of the list, plus 1 (the plus 1 is for counting the Head element of the list).