I have to write a Prolog program that finds all the matching elements between 2 separate lists. In practice it has to look like this:
?- intersect([a,c,a,b], [d,b,a,b], X).
X = [a,b]
What i have so far is this:
intersect([], Y, Z).
intersect([H| T1], Y, [H| T2]) :-
member(H, Y),
remove_all(H, T1, P),
intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :-
intersect(T1, Y, T2).
(I had to make a remove_all function in a previous exercise. This removes all the elements from a list that match what you give)
This works except for one thing, my answer looks like this:
X = [a, b|_17660]
I'm new to Prolog and don't know that much about it. Why is there a "|_17660" at the end and how would i change my code to fix it?
If someone could help me with this that would be appreciated.
First of all, you got three clean warnings about "singleton variables". That is a very clear hint that something went wrong. Usually, a Prolog programmer would fix that first. But of course, there are other ways, too.
So your problem is that you get X = [a, b|_17660] as an answer. What does this mean? The _176660 is just a variable name which has to be quantified universally. In other words the answer you got reads:
All X that start with [a, b|_] are a solution. Like [a, b] which is intended, but also ugly ones like [a, b|non_list]. Or even misleading or even incorrect ones like [a, b, c].
To understand where this problem comes from, lets focus on an implied ground query, like:
?- intersect([a,c,a,b], [d,b,a,b], [a,b|non_list]).
existence_error(procedure,remove_all/3). % ERROR: Undefined procedure: remove_all/3
Argh, you did not show the definition of remove_all/3. In a traditional programming language, we would have to stop now. But in Prolog, we still can continue. No need to see that definition. I will instead use a specialization that no longer contains remove_all/3. So in a sense, this is only part of your program, but we can still draw conclusions from it. This is what I use:
intersect([], Y, Z) :- Z = non_list.
intersect([H| T1], Y, [H| T2]) :- false,
member(H, Y),
remove_all(H, T1, P),
intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :- T2 = non_list,
intersect(T1, Y, T2).
This program is almost yours. Except that I have added extra goals to it. In another language this would not be possible. But in Prolog we can exploit a very nice property of (pure, monotonic) Prolog programs: You can add extra goals randomly and still predict what the outcome will be: The new program describes a subset of what your original program did. Of course, I had some suspicions, so my adding was somewhat guided. But you can always do the same with your buggy program!
Still not convinced? Now use that new program to see what you are actually describing:
?- intersect(Xs, Ys, Zs).
Xs = [], Zs = non_list
; ... .
?- intersect([], any, non_list).
true.
Clearly, this is not what you intended. To see where that came from, we can specialize your program even more:
intersect([], Y, Z) :- Z = non_list.
intersect([H| T1], Y, [H| T2]) :- false,
member(H, Y),
remove_all(H, T1, P),
intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :- false,
intersect(T1, Y, T2).
It should be evident by now, that the fact has to be specialized, otherwise these nonsensical solutions are possible. Here is such a specialization:
intersect([], _Y, Z) :-
Z = [].
intersect([H| T1], Y, [H| T2]) :- false,
member(H, Y),
remove_all(H, T1, P),
intersect(T1, Y, T2).
intersect([H| T1], Y, T2) :-
intersect(T1, Y, T2).
The fact reads: The intersection of the empty list and anything is the empty list. Let's leave it that way, even if Y = non_list is now possible, too.
Your rule is still removed, since I have not seen your definition. It does not matter! I will continue to find problems in the remaining program. For the moment, I have no idea, where to look for problems. But I can ask Prolog to do this for me by asking the most general query which reads like
Prolog, just tell me all solutions you can describe.
(Remember this trick, you can always ask that question - without having even the slightest idea what the predicate is about.)
?- intersect(Xs, Ys, Zs).
Xs = [], Zs = []
; Xs = [_A], Zs = []
; Xs = [_A,_B], Zs = []
; ... .
The first answer is perfect, but the second answer is not. Note that Ys does not occur anywhere, so the answer holds for all Ys. Even:
?- intersect([a], [a], []).
true.
This problem is directly related to your rule, there is no condition for it whatsoever ...
See this for a clean solution.
Related
I'm trying to find duplicate (non unique) items in a list.
For example from
duplicate([a,b,c,a,b,r,d,c], R).
I need to get [a,b,c].
I've written so far prolog program that finds duplicate elements in a list.
However, I get the answer as single elements.
R = a
R = b
R = c
And I have to get them in a list as [a,b,c]
duplicate([First|Rest], Element) :-
duplicate_first(Rest, First, Element).
duplicate_first([Head|Rest], X, X) :-
duplicate_second(Rest, Head, X).
duplicate_first([Head|Rest], _, X) :-
duplicate_first(Rest, Head, X).
duplicate_second(_, X, X).
duplicate_second([Head|Rest], _, X) :-
duplicate_second(Rest, Head, X).
P.S. I don't want to use any swi-prolog build in functions.
I find it a bit of a straightjacket to ignore the standard library. But you can fulfill the requirement by implementing the two predicates you need, which are member/2 and delete/3, yourself:
my_member(X, [X|_]).
my_member(X, [_|Xs]) :- my_member(X, Xs).
This is probably the most straightforward way to implement member/2, although it isn't exactly the same as in the SWI library.
my_delete([], _, []).
my_delete([X|Xs], X, Ys) :- my_delete(Xs, X, Ys).
my_delete([Y|Xs], X, [Y|Ys]) :- X \= Y, my_delete(Xs, X, Ys).
I just sort of took a crack at this and it seems to be OK. A better implementation would probably use something like X = Y -> ... but that can lead to issues with backtracking so I am using this variation which probably has other problems.
Now that you have the preliminaries, the actual implementation is not that hard. First your base case. There are no duplicates in the empty list.
duplicates([], []).
Now you have two inductive cases. One, in which the head of the list occurs inside the tail of the list. When that happens you add it to the result and remove it from the tail (or you'll get duplicates in your list of duplicates).
duplicates([X|Xs], [X|Ys]) :-
my_member(X, Xs),
my_delete(Xs, X, XsWithoutX),
duplicates(XsWithoutX, Ys).
Your other case is when the head element does not appear in the tail, so you can simply recur and find the rest of the duplicates:
duplicates([X|Xs], Ys) :-
\+ my_member(X, Xs),
duplicates(Xs, Ys).
I'm a little out of practice so the following code can be simplified but... given a filter function (that remove the Val correspondences from a list and return [Val] if correspondence is found or empty list otherwise)
filter(_, [], [], []).
filter(Val, [Val | Rest], [Val], LR) :-
filter(Val, Rest, _, LR).
filter(Val1, [Val2 | Rest], LO, [Val2 | LR]) :-
Val1 \= Val2,
filter(Val1, Rest, LO, LR).
and given a sort of optional adder in front of a list
addOptional([], L, L).
addOptional([O], L, [O | L]).
I suppose you can write duplicate/2 as follows
duplicate([], []).
duplicate([First | Rest], Result) :-
filter(First, Rest, Opt, Filtered),
duplicate(Filtered, Res2),
addOptional(Opt, Res2, Result).
duplicate([],[]).
duplicate([A|B],[A|B1]) :- not(member(A,B)), duplicate(B,B1).
duplicate([A|B],List) :- member(A,B), duplicate(B,List).
I wrote this predicate to remove duplicate from the list, but when I test it,
?- duplicate([a,b,c,a,d,c,b,a,e,f],N).
N = [d, c, b, a, e, f] ;
N = [d, c, b, a, e, f] ;
false.
Is there a way to just keep one result only, not two same results? (so it will only return one list).
Also, I am not allowed to use operators that modify the backtracking search, such as the cut operator !, the negation operators not, +, or the if-then-else operator with -> and ;
It would be grateful if someone could help me . :D
The actual reason for receiving more than one answer is the goal member(A,As). It produces multiple answers for duplicates in As.
?- member(a, [a,a]).
true
; true.
There are several ways out.
memberchk/2 or once/1
memberchk/2 is defined as
memberchk(X, Xs) :-
once(member(X, Xs)).
This removes alternate answers. But then, it may remove otherwise valid solutions too. Consider:
?- memberchk(X, [a,b]), b = X.
false.
?- b = X, memberchk(X, [a,b]), b = X.
b = X.
So memberchk/2 is sensitive to the precise instantiation, which makes it a very brittle, impure predicate.
But it has one good point: It sticks to just one answer for
?- memberchk(a, [a,a]).
true.
So what would be ideal is a definition that is both pure and sticking to the first element. Enter
memberd/2
memberd(X, [X|_Ys]).
memberd(X, [Y|Ys]) :-
dif(X, Y),
memberd(X, Ys).
In this definition, the recursive rule is only of relevance if the list element is different. Thus this rule will never apply to memberd(a, [a,a,a]).
Another problem in your definition is not(member(A,B)) which only behaves as intended, if A and B are sufficiently instantiated. Your definition fails for:
duplicate([a,X],[a,b]). although there is a solution: X = b.
Rather replace it by non_member/2.
Alternatively, in case you are interested in the most efficient solution, consider library(reif) available
for
SICStus and
SWI which leads to:
list_nub([], []).
list_nub([X|Xs], Ys0) :-
if_(memberd_t(X, Xs), Ys0 = Ys1, Ys0 = [X|Ys1]),
list_nub(Xs, Ys1).
Here's one way to remove all duplicates, not the most efficient but I think it's quite easy to understand the intention.
rm_duplicates(In, Out) :-
exclude(has_duplicate(In), In, Out).
has_duplicate(List, Case) :-
dif(I, J),
nth0(I, List, Case),
nth0(J, List, Case).
If you mean to make a list into a set:
list_to_set(List, Set).
It's documented: list_to_set/2
twice(X,[X|Y]):-
member(X,[Y]).
twice(X,[Y|Z]):-
twice(X,[Z]),
X\=Y.
I can't find any syntax error,but the execution fails every time.
You've got a misconception about the list structure. The list [H|T] has head element H and tail list T. So T is itself a list. If you put [T] then that's a list of only one element, that element being the list T.
Also, in your second predicate clause, you don't need the X argument or to check for X \= Y since it's not really relevant if you're checking for at least twice.
Thus, your solution changes a little to:
twice(X, [X|T]) :-
member(X, T).
twice(X, [_|T]) :-
twice(X, T).
Which says that X occurs twice in [X|T] if X is a member of T or X occurs twice in [_|T] if X occurs twice in T.
I like your intent, but cannot reproduce what you claim: that this predicate fails all the time. In fact, it loops! And here is the fragment why failure-slice:
twice(X,[X|Y]):- false,
member(X,[Y]).
twice(X,[Y|Z]):-
twice(X,[Z]), false,
X\=Y
?- twice(a,[a,a]).
Because this fragment loops, also your original program loops. Lurker has already shown you what is wrong. Here are some alternate formulations:
twice(X, Xs) :-
phrase( ( ..., [X], ..., [X], ... ), Xs).
... --> [] | [_], ... .
Nevertheless, this program has a big flaw:
?- twice(a,[a,a,a]).
true
; true
; true
; false.
Thrice the very same answer. One time is more than enough!
The ambiguity comes from the ...-non-terminal which means just any sequence. There are three ways how that matches the list [a,a,a]:
[ a, a, a ]
...,[X],...,[X], ...
...,[X], ..., [X],...
..., [X],...,[X],...
To remove the ambiguity we need to replace the ... by something more specific. In stead of anything, the sequence should match anything but X. In this way only the first match remains.
twice(X, Xs) :-
phrase( ( all(dif(X)), [X], all(dif(X)), [X], ... ), Xs).
all(_) --> [].
all(P_1) -->
[E],
{call(P_1,E)},
all(P_1).
?- twice(a,[a,a,a]).
true
; false.
That's much better. But is it the bestest? Here is a further improvement using library(reif) for SICStus|SWI.
:- use_module(library(reif)).
twice(C, [X|Xs]) :-
if_(C = X, memberd(X, Xs), twice(C, Xs) ).
memberd(C, [X|Xs]) :-
if_(C = X, true, memberd(C, Xs) ).
?- twice(a,[a,a,a]).
true.
twicee(X,[X|Y]):- member(X,Y).
twicee(X,[_|Y]):-twicee(X,Y), X\=Y.
Working code for me, check if there are two elements in a list. For example:
twicee(X,[a,a,b,b,c,d]).
X = a.
X= b.
twicee(c,[a,a,b,b,d]).
FALSE.
I'm learning swi Prolog and I wanted to create predicate that adds +2 for each element.
So I wrote something like this:
addUp([],_).
addUp([H|T],R):-addUp(T,R),is_list(R)->append([H+2],R,R);R=[H+2|[]].
addUp([1,2],X).
But it always returns false. Why?
First an advice: learn to use maplist/3: with that you will write
addUp(Xs, Ys) :- maplist(addUp2, Xs, Ys).
addUp2(X, Y) :- Y is X + 2.
or better, a more reusable snippet...
addUp(Xs, Ys) :- maplist(addUp(2), Xs, Ys).
addUp(N, X, Y) :- Y is X + N.
Anyway, arithmetic in Prolog must be evaluated 'explicitly', and your code must be simplified a lot to work
addUp([], []).
addUp([H|T], [H1|T1]) :- H1 is H+2, addUp(T, T1).
But it always returns false. Why?
Your definition does not always fail:
?- addUp([1],X).
X = [1+2].
So sometimes it succeeds. And it seems that this case is more or less what you wanted. Where else does it succeed? In other programming languages you would have to guess or, heaven forbid, read the program. In Prolog, there is no need for this. Simply find a good query. A good candidate is the most general query:
?- addUp(Xs,Ys).
Xs = [] ...
So your definition succeeds for Xs equal to [], and Ys equal to ... well, equal to anything. Therefore, this answer is too general.
Another goal catches my eye: is_list(R)->append([H+2],R,R). Let's imagine, when this will be true. For R = [] not, nor for R = [_]. In fact, there is no length, where this will be true.
Now, we can start fixing your program. See chac/CapelliC's suggestion.
I wanted to write a Prolog program to find equality of two lists, where the order of elements
doesn't matter. So I wrote the following:
del(_, [], []) .
del(X, [X|T], T).
del(X, [H|T], [H|T1]) :-
X \= H,
del(X, T, T1).
member(X, [X|_]).
member(X, [_|T]) :-
member(X, T).
equal([], []).
equal([X], [X]).
equal([H1|T], L2) :-
member(H1, L2),
del(H1, L2, L3),
equal(T, L3).
But when I give input like equal([1,2,3],X)., it doesn't show all possible values of X. Instead, the program hangs in the middle. What could be the reason?
isSubset([],_).
isSubset([H|T],Y):-
member(H,Y),
select(H,Y,Z),
isSubset(T,Z).
equal(X,Y):-
isSubset(X,Y),
isSubset(Y,X).
Try using predicate that checks if one of sets is a permutation of other set:
delete(X, [X|T], T).
delete(X, [H|T], [H|S]):-
delete(X, T, S).
permutation([], []).
permutation([H|T], R):-
permutation(T, X), delete(H, R, X).
(Predicate taken from http://www.dreamincode.net/code/snippet3411.htm)
?- permutation([1,2,3],[3,1,2]).
true
The actual reason for the non-termination that you observed is this: the following clause does not constrain L2 in any way, shape, or form.
equal([H1|T], L2) :-
member(H1, L2),
del(H1, L2, L3),
equal(T, L3).
So your query ?- equal([1,2,3], X). implies proving the goal member(_, L2) which does not terminate universally. Therefore equal([1,2,3], X) cannot terminate universally, too!
For more information on how to explain non-termination of Prolog code read about failure-slice!
PS. Looking at the termination problem from a different angle, we see that the non-termination is, in fact, a necessary consequence in this case.
Why? Because you do not constrain the number of multiplicities, which makes the solution set infinite in size. The set cannot be represented by a finite number of answers (provided you do not permit delaying goals).
If you don't care about the multiplicities of the list elements,
check for sufficient instantiation with
ground/1,
enforce it with
iwhen/2,
and eliminate duplicates with sort/2 like so:
same_elements(As, Bs) :-
iwhen(ground(As+Bs), (sort(As,Es),sort(Bs,Es))).
Sample use with SWI Prolog 8.0.0:
?- same_elements([a,c,c,b,a,c], [c,b,b,a]).
true.
?- same_elements([a,b,b,a], [b,a,b,e]).
false.
?- same_elements([a,b,b,a], Xs).
ERROR: Arguments are not sufficiently instantiated
Try this:
equal([],[]).
equal([Ha|Ta],[Hb|Tb]) :-
Ha = Hb, lequal(Ta,Tb).
How about:
equal(X, Y) :-
subtract(X, Y, []),
subtract(Y, X, []).
So why does equal([1,2,3], X) not terminate universally with your code?
Let's look at a failure-slice of your code! What are failure slices? Here's the tag info:
A failure-slice is a fragment of a Prolog program obtained by adding some goals false. Failure-slices help to localize reasons for universal non-termination of a pure monotonic Prolog program. They also help to give a lower bound for the number of inferences needed. It is a concrete program-slicing technique.
To create a failure slice:
we insert false goals into the program
while making sure that the fragment does not terminate with above goal.
del(_, [], []) :- false.
del(X, [X|T], T) :- false.
del(X, [H|T], [H|T1]) :- false,
dif(X, H), % note that the OP originally used `X \= H`
del(X, T, T1).
member(X, [X|_]).
member(X, [_|T]) :-
member(X, T).
equal([], []) :- false.
equal([X], [X]) :- false.
equal([H1|T], L2) :-
member(H1, L2), false,
del(H1, L2, L3),
equal(T, L3).
?- equal([1,2,3], _), false. % note that `false` is redundant ...
** LOOPS ** % ... as above `equal/2` cannot succeed.
So... what does above failure slice tell us? It says:
To make the goal equal([1,2,3], X) terminate universally ...
... we must change at least one of the remaining parts (the ones not striked-through)!
I suggest using built-in predicate msort/2, then comparing the lists. It takes O(nlogn) time on SWI Prolog, whereas checking unsorted lists naively element-by-element would take O(n2) time.
lists_equal(List1, List2) :-
msort(List1, Sorted1),
msort(List2, Sorted2),
Sorted1=Sorted2.
Here, sorting lists takes O(nlogn) time, and comparing them takes O(n) time on SWI Prolog, I don't know about other implementations.
Briefly
equal([],[]).
equal([H|T],[H|T1]):-equal(T,T1).