Related
I want remove all appearences of an element on a list, similar to this, but in my case, the list may have non-instantiated variables. For example:
delMember(z, [A,B,A,z], L).
L = [A, B, A];
false.
and
delMember(A, [A, B, A, z], L).
L = [B,z];
false.
I tried defining delMember as the following:
delMember(_, [], []).
delMember(X, [X|Xs], Y) :- delMember(X, Xs, Y).
delMember(X, [T|Xs], [T|Y]) :- X \== T, delMember(X, Xs, Y).
With this definition, the last result I get is correct but it's still trying to instantiate the variables before that.
?- delMember(A, [A,B,A,z], R).
A = B, B = z,
R = [] ;
A = B,
R = [z] ;
A = z,
R = [B] ;
R = [B, z] ;
any ideas???
If you look at your second predicate clause:
delMember(X, [X|Xs], Y) :- delMember(X, Xs, Y).
Unification is occurring with the X in the first and second arguments. This leads to the results you are observing when you do your query. You need to apply the same operator as you did in your third clause. So your complete predicate (with some slightly changed variable names to be more conventional) would look like:
delMember(_, [], []).
delMember(X, [X1|Xs], Ys) :- X == X1, delMember(X, Xs, Ys).
delMember(X, [X1|Xs], [X1|Ys]) :- X \== X1, delMember(X, Xs, Ys).
I want to implement a predicate P(Xs,Ys,Zs) where Xs,Ys,Zs are lists.
I'm new in Prolog and I can't find a way to get to the longest sequence in Xs (example. Xs = ['b','b','A','A','A','A','b','b']) which is included to Ys (for example Ys = ['A','A','A','A','c','A','A','A','A']) without crossing- an even number of times. Maybe someone already wrote this code ore some one can say me how can I start. Thanks for helps.
explanation of teacher.
longest_subsequence(List, Part, Subsequence):-
longest_subsequence_(List, Part, [], Subsequence).
longest_subsequence_(Xs, Ys, CurrentSubsequence, LongestSubsequence):-
append(CurrentSubsequence, Ys, NextSubsequence),
divide_list(Xs, [_LeftYs, NextSubsequence, _RightYs]), !,
longest_subsequence_(Xs, Ys, NextSubsequence, LongestSubsequence).
longest_subsequence_(_Xs, _Ys, LongestSubsequence, LongestSubsequence).
okey i did.
main_task(Xs, Ys, Zs) :-
atom_chars(Xs, Xl),
atom_chars(Ys, Yl),
retractall(record(_, _)),
assert(record(0, [])),
process(Xl, Yl, Zl),
atom_chars(Zs, Zl).
process(Xl, Yl, _) :-
get_sublist(Xl, Zl),
length(Zl, L),
record(MaxL, _),
L > MaxL,
get_index(Yl, Zl, Il),
test_even(Il),
test_intersect(Il, L),
retractall(record(_, _)),
assert(record(L, Zl)),
fail.
process(_, _, Zl) :-
record(_, Zl).
get_sublist(L1, L2) :-
get_tail(L1, L3),
get_head(L3, L2).
get_tail(L, L).
get_tail([_|T], L) :-
get_tail(T, L).
get_head([H|T1], [H|T2]) :-
get_head(T1, T2).
get_head(_, []).
get_index(Yl, Zl, Il) :-
get_index(Yl, Zl, Il, 0).
get_index([], _, [], _).
get_index([Yh|Yt], Zl, [I|It], I) :-
get_head([Yh|Yt], Zl),
!,
I1 is I + 1,
get_index(Yt, Zl, It, I1).
get_index([_|Yt], Zl, Il, I) :-
I1 is I + 1,
get_index(Yt, Zl, Il, I1).
test_even(Il) :-
length(Il, L),
L > 0,
L mod 2 =:= 0.
test_intersect([_], _).
test_intersect([X,Y|T], L) :-
Y - X >= L,
test_intersect([Y|T], L).
All lines in the list at the symbols on working with lists
Initialize the dynamic database - will be stored in it, and its maximum line length
enumerates all of the substring (sublists) from X. Bust goes double "pruning" - first place in a list of cut off the front, then from behind.
Check the length of the resulting string, if we already have a long, immediately leave for the continuation of busting
We consider a list of indexes in the occurrence of a Y, then there is every element of the list - a position in the Y, from which it includes Z.
Check the parity - just consider the length of the list of indexes, chёtnaya length - an even number of entries. And we need to check that it is greater than zero.
Check the intersection - you need to check the difference between two adjacent elements of the list of indexes, the difference should always be greater than the length Z.
If all checks are made, there is a dynamic database updates - current list Z is stored as the maximum
At the end it is a forced failure, it is rolled back to the fork in paragraph 3) and the continued search.
Note: If any check is not performed, the failure of this test is immediately rolled back to the fork in paragraph 3) and the continued search.
When the bust comes to an end, performed a second rule predicate process, it simply selects the last spicok Z in the base.
At the end of the list Z is converted back to a string
A naive approach is the following:
longest_subsequence(Xs,Ys,Zs) :-
longest_subsequence(Xs,Ys,Ys,0,[],Zs).
longest_subsequence([X|Xs],Y0,[Y|Ys],N0,Z0,Z) :-
try_seq([X|Xs],[Y|Ys],Nc,Zc),
(Nc > N0
-> longest_subsequence([X|Xs],Y0,Ys,Nc,Zc,Z)
; longest_subsequence([X|Xs],Y0,Ys,N0,Z0,Z)
).
longest_subsequence([_|Xs],Y0,[],N0,Z0,Z) :-
longest_subsequence(Xs,Y0,Y0,N0,Z0,Z).
longest_subsequence([],_,_,_,Z,Z).
try_seq([H|TA],[H|TB],N,[H|TC]) :-
!,
try_seq(TA,TB,N1,TC),
N is N1+1.
try_seq(_,_,0,[]).
here a predicate try_seq/3 aims to match as much as possible (generate the longest common subsequence) starting from the beginning of the list.
The problem is that this is a computationally expensive approach: it will have a time complexity O(m n p) with n the length of the first list, m the length of the second list and p the minimum length of the two lists.
Calling this with your example gives:
?- longest_subsequence([b,b,a,a,a],[a,a,a,c,a,a,a],Zs).
Zs = [a, a, a] ;
false.
You can make the algorithm more efficient using back-referencing, this is more or less based on the Knuth-Morris-Pratt-algorithm.
When approaching a problem, first try: divide and conquer.
When we have a list_subsequence(+List, ?Subsequence) predicate
list_subsequence([H|T], S) :-
list_subsequence(H, T, S, _).
list_subsequence([H|T], S) :-
list_subsequence(H, T, _, R),
list_subsequence(R, S).
list_subsequence(H, [H|T], [H|S], R) :- !, list_subsequence(H, T, S, R).
list_subsequence(H, R, [H], R).
we can call for library(aggregate) help:
longest_subsequence(Seq, Rep, Longest) :-
aggregate(max(L, Sub), N^(
list_subsequence(Seq, Sub),
aggregate(count, list_subsequence(Rep, Sub), N),
N mod 2 =:= 0,
length(Sub, L)
), max(_, Longest)).
edit: more library support available
A recently added library helps:
longest_subsequence_(Seq, Rep, Longest) :-
order_by([desc(L)], filter_subsequence(Seq, Rep, Longest, L)), !.
where filter_subsequence/4 is simply the goal of the outer aggregate:
filter_subsequence(Seq, Rep, Sub, L) :-
list_subsequence(Seq, Sub),
aggregate(count, list_subsequence(Rep, Sub), N),
N mod 2 =:= 0,
length(Sub, L).
How can I replace a list with another list that contain the variable to be replaced. for example
rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p]
the x to z and z doesn't change after it has been replaced.
so far I did only the one without the list
rep([], _, []).
rep(L1, H1=H2, L2) :-
rep(L1, H1, H2, L2).
rep([],_,_,[]).
rep([H|T], X1, X2, [X2|L]) :-
H=X1,
rep(T,X1,X2,L),
!.
rep([H|T],X1,X2,[H|L]) :-
rep(T,X1,X2,L).
If you use SWI-Prolog, with module lambda.pl found there : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl you can write :
:- use_module(library(lambda)).
rep(L, Rep, New_L) :-
maplist(\X^Y^(member(X=Z, Rep)
-> Y = Z
; Y = X), L, New_L).
You should attempt to keep the code simpler than possible:
rep([], _, []).
rep([X|Xs], Vs, [Y|Ys]) :-
( memberchk(X=V, Vs) -> Y = V ; Y = X ),
rep(Xs, Vs, Ys).
Of course, note the idiomatic way (thru memberchk/2) to check for a variable value.
Still yet a more idiomatic way to do: transforming lists it's a basic building block in several languages, and Prolog is no exception:
rep(Xs, Vs, Ys) :- maplist(repv(Vs), Xs, Ys).
repv(Vs, X, Y) :- memberchk(X=V, Vs) -> Y = V ; Y = X .
Here's how you could proceed using if_/3 and (=)/3.
First, we try to find a single Key in a list of pairs K-V.
An extra argument reifies search success.
pairs_key_firstvalue_t([] ,_ ,_ ,false).
pairs_key_firstvalue_t([K-V|KVs],Key,Value,Truth) :-
if_(K=Key,
(V=Value, Truth=true),
pairs_key_firstvalue_t(KVs,Key,Value,Truth)).
Next, we need to handle "not found" cases:
assoc_key_mapped(Assoc,Key,Value) :-
if_(pairs_key_firstvalue_t(Assoc,Key,Value),
true,
Key=Value).
Last, we put it all together using the meta-predicate maplist/3:
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK, succeeds deterministically
Let's improve this answer by moving the "recursive part" into meta-predicate find_first_in_t/4:
:- meta_predicate find_first_in_t(2,?,?,?).
find_first_in_t(P_2,X,Xs,Truth) :-
list_first_suchthat_t(Xs,X,P_2,Truth).
list_first_suchthat_t([] ,_, _ ,false).
list_first_suchthat_t([E|Es],X,P_2,Truth) :-
if_(call(P_2,E),
(E=X,Truth=true),
list_first_suchthat_t(Es,X,P_2,Truth)).
To fill in the "missing bits and pieces", we define key_pair_t/3:
key_pair_t(Key,K-_,Truth) :-
=(Key,K,Truth).
Based on find_first_in_t/4 and key_pair_t/3, we can write assoc_key_mapped/3 like this:
assoc_key_mapped(Assoc,Key,Value) :-
if_(find_first_in_t(key_pair_t(Key),_-Value,Assoc),
true,
Key=Value).
So, does the OP's use-case still work?
?- maplist(assoc_key_mapped([x-z,z-x,d-c]), [x,d,e,z,a,z,p], Rs).
Rs = [z,c,e,x,a,x,p]. % OK. same result as before
Building on find_first_in_t/4
memberd_t(X,Xs,Truth) :- % memberd_t/3
find_first_in_t(=(X),_,Xs,Truth).
:- meta_predicate exists_in_t(2,?,?). % exists_in_t/3
exists_in_t(P_2,Xs,Truth) :-
find_first_in_t(P_2,_,Xs,Truth).
I find your code rather confused. For one thing, you have rep/3 and rep/4, but none of them have a list in the second position where you're passing the list of variable bindings. H1=H2 cannot possibly match a list, and that's the only rep/3 clause that examines the second argument. If this is a class assignment, it looks like you're a little bit behind and I'd suggest you spend some time on the previous material.
The solution is simpler than you'd think:
rep([], _, []).
rep([X|Xs], Vars, [Y|Rest]) :- member(X=Y, Vars), rep(Xs, Vars, Rest).
rep([X|Xs], Vars, [X|Rest]) :- \+ member(X=_, Vars), rep(Xs, Vars, Rest).
We're using member/2 to find a "variable binding" in the list (in quotes because these are atoms and not true Prolog variables). If it's in the list, Y is the replacement, otherwise we keep using X. And you see this has the desired effect:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p] ;
false.
This could be made somewhat more efficient using "or" directly (and save us a choice point):
rep([], _, []).
rep([X|Xs], Vars, [Y|Ys]) :-
(member(X=Y, Vars), ! ; X=Y),
rep(Xs, Vars, Ys).
See:
?- rep([x, d, e, z, x, z, p], [x=z, z=x, d=c], R).
R = [z, c, e, x, z, x, p].
So I have this homework due tommorow. I have to filter every nth element of a list and return it as a list. So for example:
?- everyNth(3,[a,b,c,d,e,f],Rs).
Rs = [c,f].
My Idea was basically:
everynth(N, [X|Xs], L) :- everynth(N, [X|Xs], N, L).
everynth(N, [], C, L).
everynth(N, [X|Xs], 0, [X]) :- everynth(N, Xs, N, [X]).
everynth(N, [X|Xs], C, L) :- C1 is C -1,
everynth(N,Xs,C1,L).
But it does not work this way, because in the third row it tries to match X and the return X and the Count 0 the second time it goes there.
You are almost there. Check these modifications:
everynth(N, L, NL) :- everynth(N, L, N, NL).
everynth(_, [], _, []).
everynth(N, [X|Xs], 1, [X|NXs]) :- everynth(N, Xs, N, NXs).
everynth(N, [_|Xs], C, NXs) :- C1 is C-1, C1>0,
everynth(N,Xs,C1,NXs).
The first clause of everynth/4 is the termination of the recursion. It should give an empty list when there are no more items in the input list.
The second clause of everynth/4 deals with the nth item, it has to put the input item in the output list and keep processing the remaining items restarting your item counter.
And the third clause of everynth/4 deals with items which are not the nth element, so you have to skip the item, decrement the counter and continue with the remaining items.
everynth(_, _, [], R, R).
everynth(1, M, [X|Xs], Z, R) :- append(Z, [X], Z1), everynth(M, M, Xs, Z1, R).
everynth(N, M, [_|Xs], Z, R) :- N > 1, N1 is N - 1, everynth(N1, M, Xs, Z, R).
?- everynth(3, 3, [a,b,c,d,e,f], [], Rs).
Rs = [c, f] .
I'm trying to make program in prolog that will do something like this:
diffSet([a,b,c,d], [a,b,e,f], X).
X = [c,d,e,f]
I wrote this:
diffSet([], _, []).
diffSet([H|T1],Set,Z):- member(Set, H), !, diffSet(T1,Set,Z).
diffSet([H|T], Set, [H|Set2]):- diffSet(T,Set,Set2).
But in that way I can only get elements from the first list. How can I extract the elements from the second one?
#edit:
member is checking if H is in Set
member([H|_], H).
member([_|T], H):- member(T, H).
There is a builtin that remove elements from the list:
diffSet([], X, X).
diffSet([H|T1],Set,Z):-
member(H, Set), % NOTE: arguments swapped!
!, delete(T1, H, T2), % avoid duplicates in first list
delete(Set, H, Set2), % remove duplicates in second list
diffSet(T2, Set2, Z).
diffSet([H|T], Set, [H|Set2]) :-
diffSet(T,Set,Set2).
Or using only built-ins. if you wanted to just get the job done:
notcommon(L1, L2, Result) :-
intersection(L1, L2, Intersec),
append(L1, L2, AllItems),
subtract(AllItems, Intersec, Result).
?- notcommon([a,b,c,d], [a,b,e,f], X).
X = [c, d, e, f].
Deliberately avoiding the built ins for this that #chac mentions, this is an inelegant way that does the job.
notcommon([], _, []).
notcommon([H1|T1], L2, [H1|Diffs]) :-
not(member(H1, L2)),
notcommon(T1, L2, Diffs).
notcommon([_|T1], L2, Diffs) :-
notcommon(T1, L2, Diffs).
alldiffs(L1, L2, AllDiffs) :-
notcommon(L1, L2, SetOne),
notcommon(L2, L1, SetTwo),
append(SetOne, SetTwo, AllDiffs).
? alldiffs([a,b,c,d], [a,b,e,f], X).
X = [c, d, e, f] .