Related
I need to write a predicate next(X, List1, List2), which returns List2, an array of elements which directly follow X.
For example,
next(v1,[v1,v2,v3,v1,v2,v1,v5],L) returns L=[v2,v2,v5]
next(b,[b,k,m,b,j],L) returns L=[k,j]
next(s,[s,b,c,d,e,f,s,c,s,g],L) returns L=[b,c,g]
....
I know that recursion and tail must be used.
I think I know the logic and how the predicate should work, but I can't get it to work. Below is how I'd expect the predicate to work if user entered next(a,[a,b,c,a,b,c],L).
[a,b,c,a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
%first letter is a, put b in array L, remove a from initial array.
[b,c,a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is b, it is not a, so remove it from initial array
[c,a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is c, it is not a, so remove it from initial array
[a,b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is a, put b in array L, remove a from initial array.
[b,c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is b, it is not a, so remove it from initial array
[c]
%if first letter is a, put the letter after it in array L, if not - remove first letter.
% first letter is c, it is not a, so remove it from initial array
This is what I have:
next(X, List1, List2):-
next(X,[X,X2|List1],X2).
I know the part in square brackets is wrong.
Update #1:
/* X is the head of the list */
next(X, [X,Y|T1], [Y|T2]) :-
next(X, [Y|T1], T2).
/* X is not the head of the list*/
next(X, [_|T1], [T2]) :-
next(X, T1, T2).
/* T1 contains only one element */
next(X, _, [T2]):-
true.
/* T1 is empty */
next(X,[T2]):-
true.
Trace log for Update #1:
1 ?- trace.
true.
[trace] 1 ?- next(a,[a,c,d,e,f,a,g],S).
Call: (6) next(a, [a, c, d, e, f, a, g], _G4792) ? creep
Call: (7) next(a, [c, d, e, f, a, g], _G4880) ? creep
Call: (8) next(a, [d, e, f, a, g], _G4885) ? creep
Call: (9) next(a, [e, f, a, g], _G4888) ? creep
Call: (10) next(a, [f, a, g], _G4891) ? creep
Call: (11) next(a, [a, g], _G4894) ? creep
Call: (12) next(a, [g], _G4898) ? creep
Call: (13) next(a, [], _G4903) ? creep
Exit: (13) next(a, [], [_G4906]) ? creep
Exit: (12) next(a, [g], [[_G4906]]) ? creep
Exit: (11) next(a, [a, g], [g, [_G4906]]) ? creep
Exit: (10) next(a, [f, a, g], [[g, [_G4906]]]) ? creep
Exit: (9) next(a, [e, f, a, g], [[[g, [_G4906]]]]) ? creep
Exit: (8) next(a, [d, e, f, a, g], [[[[g, [_G4906]]]]]) ? creep
Exit: (7) next(a, [c, d, e, f, a, g], [[[[[g, [_G4906]]]]]]) ? creep
Exit: (6) next(a, [a, c, d, e, f, a, g], [c, [[[[g, [_G4906]]]]]]) ? creep
S = [c, [[[[g, [_G4906]]]]]]
I have gone through a list of prolog exercises of basic level from these resources:
http://www.ic.unicamp.br/~meidanis/courses/problemas-prolog/
http://www.anselm.edu/homepage/mmalita/culpro/index.html
I think you've defined what rules you need to solve the problem, but your predicate clauses that define these rules aren't all correct. Let's look at the rules you've defined:
/* X is the head of the list */
next(X, [X,Y|T1], [Y|T2]) :-
next(X, [Y|T1], T2).
This is the one I gave in a comment where the head of the list matches the element, and it's correct.
/* X is not the head of the list*/
next(X, [_|T1], [T2]) :-
next(X, T1, T2).
This clause has an issue. It says, X is not the head of the list, but the query next(a, [a,b,c], T) will match it, since X = _ is possible. Also, and here's where all of your extra brackets came in, T2 is already a list, so you don't want to put it into brackets like, [T2]. The corrected clause is:
next(X, [Y|T1], T2) :-
dif(X, Y), % Or X \== Y if you don't have dif/2
next(X, T1, T2).
The third rule and clause:
/* T1 contains only one element */
next(X, _, [T2]):-
true.
This has an issue because _ matches anything, not just single element lists. The rule says, T1 contains only one element. But T1 doesn't even appear in the clause. The corrected version would be:
/* A list with one element has no elements "next" */
next(_, [_], []).
So in the above, it no longer matters what the first argument is, and the 2nd argument is any list of one element, no matter what it is. The result must be empty.
And your last rule & clause:
/* T1 is empty */
next(X,[T2]):-
true.
One glaring issue is that you now just have 2 arguments. Your predicate must have 3. And if T1 is empty, I would expect the middle argument to be []:
/* An empty list has no "next" values */
next(_, [], []).
You could also combine the last two clauses as:
next(_, T, []) :- T = [] ; T = [_].
I have the following problem:
Define a predicate sorted(LL), that is satisfied when the list LL
contains other lists that are sorted in order of increasing length.
For example:
?- sorted([[],[1],[1,1],[1,1,1]]) -> yes.
?- sorted([[],[1],[1,1]]) -> yes.
?- sorted([[1],[],[1,1],[1,1,1]]) -> no.
And I have this code so far:
% shorter/2
shorter([],_).
shorter([_|T1], [_|T2]) :- shorter(T1,T2).
% sorted/1
sorted([]).
sorted([_]).
sorted([L1,L2 | T]) :- shorter2(L1, L2), sorted([L2,T]).
The problem is contained in the above line: sorted([L2,T]). When only one element is left in the list of lists, that call will append an empty list [] because of which shorter/2 will fail. It is depicted in the following SWIPL trace.
[trace] ?- sorted([[1],[2,3]]).
Call: (6) sorted([[1], [2, 3]]) ? creep
Call: (7) shorter2([1], [2, 3]) ? creep
Call: (8) shorter2([], [3]) ? creep
Exit: (8) shorter2([], [3]) ? creep
Exit: (7) shorter2([1], [2, 3]) ? creep
Call: (7) sorted([[2, 3], []]) ? creep <-- empty list appended
Call: (8) shorter2([2, 3], []) ? creep
Fail: (8) shorter2([2, 3], []) ? creep
Fail: (7) sorted([[2, 3], []]) ? creep
Fail: (6) sorted([[1], [2, 3]]) ? creep
#PauloMoura already gave you the right answer. Is there anything to learn about this? How did you encounter that problem? And how can you locate such problems systematically? I assume that you did not jump into the debugger to look at all those traces for sheer curiosity and a low on supply of animated gifs.
You rather encountered a problem. That is, you had the goal sorted([[1],[2,3]]). which you expected to succeed, but it did not. So you had here some unexpected failure. Sometimes also called insufficiency or incompleteness. This means that the definition for sorted/1 is too specialized, it describes a set of solutions that is too small — at least it misses sorted([[1],[2,3]]).
It often helps to minimize the problem, first. Also sorted([[],[3]]) fails, although we expect it to succeed. And sorted([[],[]]) even loops.
Understanding non-termination
Loops? That's often even easier to localize in a pure Prolog program. I will add goals false and goals like T = [] into the program. The resulting program fragment (called a failure slice) certainly will become completely dysfunctional. But it will retain a very nice property. For: if this new fragment loops, then also the original program will loop. Here is that program that still loops:
?- sorted([[],[]]), false.
sorted([]) :- false.
sorted([_]) :- false.
sorted([L1,L2 | T]) :- T = [], L1 = [], L2 = [],
shorter(L1, L2),
sorted([L2,T]).
shorter([],_).
shorter([_|T1], [_|T2]) :- false,
shorter(T1,T2).
in other words:
sorted([[],[]]) :-
shorter([],[]),
sorted([[],[]]).
So, procedurally speaking, that rule does not (always) reduce the length of the list.
Concluding reading
Another way to understand the problem is to read the recursive rule right-to-left in the direction the arrow is pointing. Actually, :- is meant to symbolize ←, well, 1970s style (listen to this French 1972 summerhit to until you understand). So let's try this. I will read:
sorted([L1,L2 | T]) :- shorter2(L1, L2), sorted([L2,T]).
^^^^^^^^^^^^^^ starting here
I start on the right side and interpret this as:
Provided, sorted([L2,T]) is true.
Maybe some extra remark: Now, you might get pretty uneasy. You might say: Who knows this? Maybe that is not true at all! But the point is, it's just conditional. OK?
and provided shorter(L1, L2) is true
then, we can conclude that sorted([L1, L2|T]) is true.
So we take a list of length 2 as granted and conclude that a list of length 2 or more holds as well.
But where do we actually state that a list of length 2 holds? There is no other place than this rule. Thus: Nowhere is this stated. And thus lists of length 2 or longer will never be sorted.
You have two typos in the last clause of the sorted/1 predicate, which should be:
sorted([L1,L2| T]) :- shorter(L1, L2), sorted([L2| T]).
In the quest of learning more about prolog (and in the interest of solving my assignment), I have come across a situation where I need to compare 2 lists and find out if AT LEAST ONE element match ...
Here is an example what I want to do:
?-match([a,b,c],[x,y,z]).
no.
?-match([a,b,c],[x,y,b]).
yes.
My solution up to now:
compare_list([],[]).
compare_list([],_).
compare_list([L1Head|L1Tail],List2):-
member(L1Head,List2),
compare_list(L1Tail,List2).
but this solution gives a true when all the members of List1 are present in List2!
Please people, don't think that I am cheating on an assignment, the problem is much much more complex, I am just stuck at this point and need help to get out of this sticky corner... otherwise I have done the entire assignment myself!
your problem can be solved using the simpler builtins
match(L1,L2) :- member(E,L1),member(E,L2). % full join
add the nasty cut if you are really interested only in 'at least one' solution
match(L1,L2) :- member(E,L1),memberchk(E,L2),!. % really, just the first!
I'll comment on the attempt you've made, which is close, but not quite there:
compare_list([],[]).
compare_list([],_).
The first clause for compare_list/2 says that the empty list has at least one element in the empty list. The second says the empty list has at least one element in any other list. So the first clause is redundant (it's already covered by the second). Whether you want this to be true (that an empty list has an element in any other list) is up to you. Since an empty list has no members, one might consider this a failure case (and, thus, not be declared as true) but you can call it true by definition if you wish. However, it will cause some issues in the recursive case once you have your predicate correctly defined since reducing down to [] will become true and ultimately it might find any list has elements in any list (oops!). I'd leave these two clauses out and consider this case a fail.
compare_list([L1Head|L1Tail], List2):-
member(L1Head, List2),
compare_list(L1Tail, List2).
This says that the first list has an element in the second list if: (1) the head of the list is a member of the second list, AND (2) the tail of the first list has an element in the second list. Does this sound logically correct? If you think this through, given there are no additional compare_list/2 clauses, this is true only if EVERY element of the first list is a member of the second list, as you have observed.
Finally, you're missing the case where the first list has a head that is not a member of the second list. This shouldn't necessarily be a failure since the tail of the first list may have a member in the second list, even if the first element (head) is not a member.
Another way is to use nth0 predicate.
match(L1, L2) :-
nth0(_, L1, SharedItem),
nth0(_, L2, SharedItem).
The first nth0 says "is there a L1 list item with index '_' (ie don't care whether it is in first, second etc. position in the list), whose name is variable SharedItem.
The second nth0 does the same for L2.
But the nice trick is in the unification.. by using the same variable name SharedItem on both nth's, prolog will continue iterating through the lists until the same item is in both.
As always the 'trace.' predicate is your best friend.. run it before calling the above to see what prolog is doing in the background:
[trace] ?- match([a,b,c],[x,y,b]).
Call: (6) match([a, b, c], [x, y, b]) ? creep
Call: (7) lists:nth0(_G1965, [a, b, c], _G1967) ? creep
Exit: (7) lists:nth0(0, [a, b, c], a) ? creep
Call: (7) lists:nth0(_G1968, [x, y, b], a) ? creep
Fail: (7) lists:nth0(_G1968, [x, y, b], a) ? creep
Redo: (7) lists:nth0(_G1968, [a, b, c], _G1970) ? creep
Exit: (7) lists:nth0(1, [a, b, c], b) ? creep
Call: (7) lists:nth0(_G1968, [x, y, b], b) ? creep
Exit: (7) lists:nth0(2, [x, y, b], b) ? creep
Exit: (6) match([a, b, c], [x, y, b]) ? creep
true .
So the 'outer' loop is L1.. it first tries index 0 of L1(a), then when it fails to find it in L2, it does a Redo (of the first nth0), but this time with index 1(b), and finds it, then returns true.
Using your example predicate match/2. The solution is as simple as traverse recursively the List1 (on the left) and check if the Head belongs to the List2 via the memberchk/2 predicate. The reason to use memberchk/2 is that it succeeds only once (i.e., not re-executable on backtracking) and this is what your "AT LEAST ONE" condition states. If the List1 is empty, the predicate fails.
Code:
match([Head|Tail], List2):-
memberchk(Head,List2).
match([_|Tail],List2):-
match(Tail,List2).
Examples:
| ?- match([a,b,c],[x,y,z]).
no
| ?- match([a,b,c],[x,y,b]).
yes
| ?- match([a,b,c],[]).
no
| ?- match([],[x,y,b]).
no
del(X,[X|Reszta],Reszta).
del(X,[Y|Ogon],[Y|Reszta]) :- del(X,Ogon,Reszta).
I don't understand this code. If I ask:
?- del(c, [a,b,c],X).
Compiler will go to the second line, and he will trigger a recursion loop del(x,[b,c],[]). Am I right?
You can see how the interpreter works by typing (well, in swi-pl at least, should be something similar in other implementations) :
?- trace, del(c, [a,b,c],X).
BTW, you certainly forgot to include a line such as :
del(_, [], []).
Else the algorithm doesn't initialize the result list.
Then it's really basic : if the first element of the list is unifiable with the one you want to remove, you skip it, else, you include it in the result list.
So basicly here, it will work like that :
del(c, [a, b, c], X) => c can't be unified with a so we will include a when constructing the list from the end.
del(c, [b, c], X) => c can't be unified with b so we will include b when constructing the list from the end.
del(c, [c], X) => c can be unified with c so we won't include c when constructing the list from the end.
del(c, [], X) => [] is true when X = [] so let's say X = [] and now let's construct our result list by climbing up the recursion :
X = [] when climbing up one step because c isn't included.
X = [b] when climbing up one step because b is included.
X = [a, b] when climbing up one step because a is included.
use trace/0 to see what will happen. in this case:
4 ?- trace.
true.
[trace] 4 ?- del(c,[a,b,c],X).
Call: (6) del(c, [a, b, c], _G531) ? creep
Call: (7) del(c, [b, c], _G607) ? creep
Call: (8) del(c, [c], _G610) ? creep
Exit: (8) del(c, [c], []) ? creep
Exit: (7) del(c, [b, c], [b]) ? creep
Exit: (6) del(c, [a, b, c], [a, b]) ? creep
X = [a, b] .
at each "turn" prolog will check if the first element is the one we want to remove.
if it is, we are done.
otherwise, we keep the head and recursively call del/3 for the tail of the list
whether or not we should think about what happens if the element is not in the given list is another matter; we might want the predicate to fail in that case, we might want to return the whole list and then we should add the del(_, [], []). as mog said
for example..
insert(X,Ys,[X|Ys]).
insert(X,[Y|Ys],[Y|Zs]) :- insert(X,Ys,Zs)
why the use of Zs as a variable.. the base case is obviously simple.. head of X::YS.
but the recursive statement is going to be a continuation from the 1st goal.
so for insert(a,[b,c],L) you get L=[a,b,c]
second time around you get [b,a,c]
third time you get [b,c,a]
but what is the actual technical definition of Zs in the program?
[trace] 1 ?- insert(a,[b,c],L).
Call: (6) insert(a, [b, c], _G522) ? creep
Exit: (6) insert(a, [b, c], [a, b, c]) ? creep
L = [a, b, c] ;
Redo: (6) insert(a, [b, c], _G522) ? creep
Call: (7) insert(a, [c], _G595) ? creep
Exit: (7) insert(a, [c], [a, c]) ? creep
Exit: (6) insert(a, [b, c], [b, a, c]) ? creep
L = [b, a, c] ;
Does the continuation begin at the recusive call? Meaning that the 1st goal ended # the base case.. so we start next time # the recursive? Also I can see start using different variable locations for L (aka _G522 vs _G595).
Zs is the result of inserting X into Ys.
In Prolog, you don't usually speak of continuations, but of choice points. When insert(a,[b,c],L) has returned its first result and you start backtracking, the Prolog compiler goes back up into the call chain to find the last choice point:
the last operation was execution of insert's first clause, which was deterministic and bound L;
before that, the last operation was choosing between both clauses, which was a choice point.
Since at this choice point, the first clause was selected, the second one is chosen upon backtracking, causing Zs to be bound in the predicate. L is unbound by backtracking from the first clause and re-bound when the second option returns.
There are no continuations in Prolog, but there's built in backtracking.
To be honest it took me some time too to understand the program.
The thing is that Prolog heavily relies on pattern matching, and choicepoints are inserted when there's more than one pattern that matches. If you want a deterministic program (i.e. without choicepoints) you have to ensure that at a time only one pattern matches (this is the recommended way), or the undesired execution path fails somewhere (this means you throw away all the calculations done in this path). The simplest way to ensure one choicepoint is using the cut operator (!/0).
"what is the actual technical definition of Zs in the program?"
In Prolog you don't have to declare variables, they can be introduced anywhere, and where they get bound (get an actual value, that's immutable) is sometimes hard to follow. Without the first predicate there would be always an unbound variable at the and of the second list, but that variable gets bound when being unified with [X|YS] in the first predicate after the recursive call. As the first predicate doesn't contain a body, the program terminates, and offers a solution to the user. As you see your program can't terminate in the second predicate, only in the first, but that's not surprising from a recursive function, just think of the classic factorial example.
factorial(0,1).
factorial(N,F) :-
N>0,
N1 is N-1,
factorial(N1,F1),
F is N * F1.