I want to remove consecutive duplicates in a list in prolog. Im new to the language so I am having a hard time understanding how everything works. So far here is what I've come up with:
remove_con_dups([X],L) :- L = X.
remove_con_dups([X,Y|_],L) :- X \= Y, L = X.
remove_con_dups([_|T],L) :- remove_dups(T,L).
so far if I query remove_con_dups([a,a,a,b,b,a,c],X), it will give me these values
X = a,
X = b,
X = a,
X = c.
What I want is to have
X = [a,b,a,c].
I just can't seem to get my head around this. Any help?
Thanks
remove_con_dups([X,Y|_], L) :- X \= Y, L = X.
fully defines the second argument, L, with respect to its connection with the first argument;
remove_con_dups( [X,Y|_], LL) :- X \= Y, L = X, LL = [L|T].
partially defines the second argument, LL, as a list with L at its head.
What remains is to say something about its tail, T:
remove_con_dups( [X,Y|R], LL) :- X \= Y, L = X, LL = [L|T],
remove_con_dups( R, T).
The above might not be quite right. Is it R? Is it [Y|R]? That's for you to define.
I think could be simpler, if you handle the positive case only, discarding the first duplicate seen by pattern matching (that is, the head' arguments shape):
remove_con_dups([],[]).
remove_con_dups([X,X|T],R) :- remove_con_dups([X|T],R).
remove_con_dups([H|T],[H|R]) :- remove_con_dups(T,R).
This fragment needs a cut somewhere, I'll leave as an easy exercise to find the position where to insert it.
Related
I'm trying to create a rule called redundancy that examines lists to see if two elements appear together in more than one list.
Here is my code:
columns([a,b,c]).
columns([b,c,d]).
in(X, [H|_]) :-
X = H.
in(X, [_|T]) :-
in(X, T).
redundancy(X, Y) :-
columns(A),
columns(B),
A \= B,
X \= Y,
in(X, A),
in(X, B),
in(Y, A),
in(Y, B).
The problem is the constraint X \= Y. I want it in there to exclude instances where X and Y are identical elements, which would be true for all single elements that appear in more than one list. But it only returns false for the given columns even though it should return permutations of b and c.
?- redundancy(U, T).
false.
If I comment out the constraint I get the expected elements along with the unwanted ones mentioned above.
?- redundancy(X, Y).
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = b ;
X = Y, Y = c ;
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = b ;
X = Y, Y = c ;
false.
Is there a way to enforce this constraint? I'm also interested in ideas to restrict results to a given combination of elements rather than permutations.
Simply move X \= Y to the last line of your predicate. also, see prolog-dif and instantiation-error.
The thing to avoid is using non-pure predicates with not-yet-instantiated logical variables (unless this is exactly what you intended, and you know what you're doing).
Another thing to notice is that X \= Y is not a constraint (that's dif), but a check.
I've been searching for something that might help me with my problem all over the internet but I haven't been able to make any progress. I'm new to logic programming and English is not my first language so apologize for any mistake.
Basically I want to implement this prolog program: discord/3 which has arguments L1, L2 lists and P where P are the indexes of the lists where L1[P] != L2[P] (in Java). In case of different lengths, the not paired indexes just fail. Mode is (+,+,-) nondet.
I got down the basic case but I can't seem to wrap my head around on how to define P in the recursive call.
discord(_X,[],_Y) :-
fail.
discord([H1|T1],[H1|T2],Y) :-
???
discord(T1,T2,Z).
discord([_|T1],[_|T2],Y) :-
???
discord(T1,T2,Z).
The two clauses above are what I came up to but I have no idea on how to represent Y - and Z - so that the function actually remembers the length of the original list. I've been thinking about using nth/3 with eventually an assert but I'm not sure where to place them in the program.
I'm sure there has to be an easier solution although. Thanks in advance!
You can approach this in two ways. First, the more declarative way would be to enumerate the indexed elements of both lists with nth1/3 and use dif/2 to ensure that the two elements are different:
?- L1 = [a,b,c,d],
L2 = [x,b,y,d],
dif(X, Y),
nth1(P, L1, X),
nth1(P, L2, Y).
X = a, Y = x, P = 1 ;
X = c, Y = y, P = 3 ;
false.
You could also attempt to go through both list at the same time and keep a counter:
discord(L1, L2, P) :-
discord(L1, L2, 1, P).
discord([X|_], [Y|_], P, P) :-
dif(X, Y).
discord([_|Xs], [_|Ys], N, P) :-
succ(N, N1),
discord(Xs, Ys, N1, P).
Then, from the top level:
?- discord([a,b,c,d], [a,x,c,y], Ps).
Ps = 2 ;
Ps = 4 ;
false.
How can I get my Prolog program to output
1*a*b*c
If I input simplify([1,a,b,c],S).?
At the moment the result would be
1*(a*(b*c)).
simplify(S,S1):-
s(S,S1).
s([H|T],C) :- T\=[],s(H,SA), s(T,SB), s0(SA*SB,C).
s([H|T],H) :- T==[].
s(A,A).
s0(A*B,S):-
S = A*B.
Thanks for your help.
The difference between 1*a*b*c and 1*(a*(b*c)) is associativity, i.e., the position of the parentheses:
?- X = 1*a*b*c, X = ((One * A) * B) * C.
X = 1*a*b*c,
One = 1,
A = a,
B = b,
C = c.
One way to do this is to "fold over the list from the left", that is to say, compute a result for the first element of the list, combine with the second element, then the third, etc. This is typically done using an accumulator argument to pass the intermediate result. In contrast, your recursion folds the list "from the right" (combining a result for the tail list with the first element, instead of the initial list with the last element).
Here's a way (very lightly tested):
list_multexp([X|Xs], Multexp) :-
list_multexp(Xs, X, Multexp). % use first element as initial acc
list_multexp([X], Acc, Acc * X).
list_multexp([X|Xs], Acc, Multexp) :-
dif(Xs, []),
list_multexp(Xs, Acc * X, Multexp).
This works for your example:
?- list_multexp([1,a,b,c], Multexp).
Multexp = 1*a*b*c ;
false.
Depends on what Prolog you're using. SWI has foldl/4 built in, which is like "reduce" in other languages. So, you could simplify your program to the following:
s(B,A,A*B).
simplify([H|L],E):- foldl(s,L,H,E).
Not sure that is what do you want but... using atom_concat/3...
simplify([H],H).
simplify([A | T], D) :-
simplify(T,B),
atom_concat(A, '*', C),
atom_concat(C, B, D).
But you have to use 1 as an "atom", so
simplify(['1',a,b,c], S),
This question already has answers here:
Prolog, X before Y in a List
(4 answers)
Closed 6 years ago.
I am going to write predicate which is true iff only and only when element X occurs before Y on list L
before(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
Above, you can see my solution. What do you think about it ?
When it comes to my specific question:
My predicate returns true when there is exists at least one pair that Y followed X. How to define predicate such that it is true for each pair ?
The solution you show works for the "if one exists" case, but is somewhat imperative in nature. That is, it's a little bit like a C program translated to Prolog. Imperative means you are telling the computer, using the programming language, what steps to execute in order to achieve your results.
To be more declarative or relational, your "exists" solution could be expressed nicely as a DCG:
... --> [].
... --> [_], ... .
before(X, Y) --> ... , [X], ... , [Y], ... .
(NOTE: You can in Prolog have a predicate named ..., which is shown here.) This describes the relationship of X and Y in the list. It does not describe steps to execute, but instead describes the relationship of X and Y in a sequence. This solution has been shown before on SO.
Following this approach (where we describe the relationship of X and Y), one way (not necessarily the only way) to express that all the X precede all the Y would be:
before_all(X, Y) -->
{ dif(X,Y) },
any_sequence_but(Y), [X], any_sequence_but(Y), [Y], any_sequence_but(X).
any_sequence_but(_) --> [].
any_sequence_but(Y) --> [X], { dif(X,Y) }, any_sequence_but(Y).
Which yields a solution like this:
?- phrase(before_all(X,Y), [b,a,b,c,a,b,d]).
X = b,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
X = c,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
false.
?-
If the condition should hold for all pairs, the condition should hold for at least one pair, while its converse shouldn't be true for any pair.
I took the liberty of renaming your before/3 to beforeSome/3.
beforeSome(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).
Which yields the desired results:
?- beforeAll([1,2,3,1,4,5], 1, 4).
true.
?- beforeAll([1,2,3,1,4,5], 1, 2).
false.
Please note that your use of nth1/3 precludes it being used with uninstantiated variables. In other words, beforeAll([1,2,3,1,4,5], X, Y). is false.
A better implementation of beforeSome/3 would be something like
beforeSome([X|T], X, Y) :-
member(Y, T).
beforeSome([_|T], X, Y) :-
beforeSome(T, X, Y).
% no change needed, but repeated here for completeness' sake
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).
I have the following prolog code. The link predicate refers to another file containing various links such as:
link(b,brown,j)
I am using the member predicate to attempt to control the looping in this route program. The idea is if I have been to a certain position before, the program will not try to go down that route.
However, when I try to trace the program to see where it is going wrong, when it checks to see if the position is a member in the positions list, the first position is already in the list so the program always tries another route after that point when it shouldn't. Anyone know how to fix this?
member(X,[X|_]).
member(X,[_|Xs]):- member(X,Xs).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
\+member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]),
!.
Some minor comments first: You do not need that cut at all. If you really want to restrict the predicate to exactly one answer, do it at the top using once/1. That is not only conceptually cleaner, it is even more efficient.
The other problem you had is related to Prolog's unsafe negation. If you, accidentally as you did, hand over a goal that is too general, the negation will always fail. In other words: negation is next-to-broken in Prolog. There are two ways out: Either produce an error for such cases or simply use a better definition like non_member/2.
Let's see what would have happened with non_member/2 in place:
link(b,brown,j).
route(X,X,[X],_).
route(X,Z,[X|Path],Positions):-
link(X,Colour,Y),
% \+member([Y,Colour],Positions),
non_member([Y,Colour],Positions),
route(Y,Z,Path,[[Y,Colour]|Positions]).
non_member(E, Es) :-
maplist(dif(E), Es).
?- route(X,Y,Path,Rs).
Y = X, Path = [X]
; X = b, Y = j, Path = "bj", Rs = []
; X = b, Y = j, Path = "bj", Rs = [_A],
dif([j,brown],_A)
; X = b, Y = j, Path = "bj", Rs = [_A,_B],
dif([j,brown],_A), dif([j,brown],_B)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C),
dif([j,brown],_D)
; X = b, Y = j, Path = "bj", Rs = [_A,_B,_C,_D,_E],
dif([j,brown],_A), dif([j,brown],_B), dif([j,brown],_C),
dif([j,brown],_D), dif([j,brown],_E)
; ... .
So all answers describe the same Path = "bj" (short form for [b,j]). But the last argument now is a list of elements that all must be different to [j,brown]. So the best would have been:
route(X, Y, Path) :-
route(X, Y, Path, []).
And here is an alternate definition reusing path/4. I am not really sure what you mean by these colors. Nevertheless:
clink(X-_, Y-Color) :-
link(X, Color, Y).
route(X, Y, Path) :-
path(clink, Path, X-none, Y-_).
or even shorter using library(lambda):
route(X, Y, Path) :-
path(\ (Xl,_)^(Yl^C)^clink(Xl,C,Yl), Path, X-none, Y-_).