I'm quite new to declarative programming as a whole and am having trouble understanding how to properly recursively create a list of "moves" using tail recursion. In Prolog, I've been aimlessly tinkering for hours and false/gtrace can only tell me so much. I'd really appreciate any advice!
% Recursive Step
path([LF1, LH1, B1, RF1, RH1], [LF2, LH2, B2, RF2, RH2], Explored, Moves) :-
move([LF1, LH1, B1, RF1, RH1], [LF3, LH3, B3, RF3, RH3]),
not(member([LF3, LH3, B3, RF3, RH3], Explored)),
path([LF3, LH3, B3, RF3, RH3],
[LF2, LH2, B2, RF2, RH2],
[[LF3, LH3, B3, RF3, RH3]|Explored],
[[[LF3, LH3, B3],[LF1, LH1, B1]] | Moves]).
% Solution found
path([LF,LH,B,RF,RH],[LF,LH,B,RF,RH],[], []).
solve(P) :- path([3,3,1,0,0],[0,0,0,3,3], _, P).
Rather use this generic definition for path/4!
solve(Path) :-
path(move, Path, [3,3,1,0,0],[0,0,0,3,3]).
Do it the other way around:
path([LF1, LH1, B1, RF1, RH1], [LF2, LH2, B2, RF2, RH2],
Explored, [[[LF3, LH3, B3],[LF1, LH1, B1]] | Moves]) :-
move([LF1, LH1, B1, RF1, RH1], [LF3, LH3, B3, RF3, RH3]),
not(member([LF3, LH3, B3, RF3, RH3], Explored)),
path([LF3, LH3, B3, RF3, RH3],
[LF2, LH2, B2, RF2, RH2],
[[LF3, LH3, B3, RF3, RH3]|Explored],
Moves).
path([LF,LH,B,RF,RH],[LF,LH,B,RF,RH],[], []).
This builds the list in the top-down manner.
(I haven't looked closely at your code, just referred to what you've asked).
Related
I am writing a predicate in Prolog to divide a list into two equal in length lists. For example :
spliting([a, b, c, d, e], L1, L2)
produces:
L1 = [a, b, c], L2 = [d, e].
My code:
parimpar(L, A, B) :-
split(L, L, A, B).
split(B, [], [], B).
split([H|T], [_, _|T1], [H | T2], B) :-
split(T, T1, T2, B).
But it is working only the list to split is of even length.
How can I resolve that?
I try to define replaceEltByclass(E1:list,E2:list) E is a list without sublist. each element of E1 belonging to a class C is replaced by the
elements of C. The final result is put in E2. For example, the goal rep_class([e1,e4,e6,e11], E2) will provide the list E2 : [[e1,e8,e10], e4,[e3,e6,e7],e11]. I don't have the good results.
/*The code*/
/*facts*/
class(c1,[e3, e6, e7]).
class(c2,[e1, e8, e10]).
/*rules*/
rep_class([],[]).
rep_class([E|Q],E2) :-
class(C,L),
not(member(E,L)),
concat(E2,E,E2),
rep_class(Q,E2).
rep_class([E|Q],E2) :-
class(C,L),
member(E,L),
concat(E2,L,E2),
rep_class(Q,E2).
/*conventional concat*/
concat([],L,L).
concat([H|T],L,[H|Res]) :- concat(T,L,Res).
The problem is in: class(C,L),not(member(E,L)), because it will give two solution one if C=C2 and then for example e1 belongs in C2 so it will replace it with L and one solution when C=C1 where it will leave it as e1. You need to write "does C exists such member(e1,L)??" so you have to collect all possible lists and see if member(e1,L) stands for a list L. So with some changes my version is :
class(c1,[e3, e6, e7]).
class(c2,[e1, e8, e10]).
rep_class([],[]).
rep_class([E|Q],[E|E2]) :-
findall(L,class(_,L),List),
not(find(List,E,_)),
rep_class(Q,E2).
rep_class([E|Q],[Lout|E2]) :-
findall(L,class(_,L),List),
find(List,E,Lout),
rep_class(Q,E2).
find([Lin|_],E,Lin):-member(E,Lin).
find([Lin|T],E,Lout):-not(member(E,Lin)),find(T,E,Lout).
As an example:
?- rep_class([e1,e4,e6,e11], E2).
E2 = [[e1, e8, e10], e4, [e3, e6, e7], e11] ;
false.
I'm working on a problem to flatten only one level of a list in Prolog. For example, [[1],[2,3]] would become [1,2,3], but [[1,[2]],3] would only flatten down to [1,[2],3]. I went through some other questions on the site, but none thoroughly answered this question, and I just can't get my code to work on all my test cases.
Update: the code works! Here is the eventual answer that I came to:
my_flatten([], []).
my_flatten([A|B],L) :- is_list(A), my_flatten(B,B1), !, append(A,B1,L).
my_flatten([A|B],[A|B1]) :- my_flatten(B,B1).
You need 3 simple clauses, I will show just the most complex one
flat([H|T],R) :- is_list(H), flat(T,T1), append(H,T1,R).
other two clauses are the base recursion case, and a copy as is of head to result.
You should also place a cut in the clause I've shown, otherwise on backtracking you'll get wrong results (due to firing of the clause copy as is)
This are the results obtained with the predicate described at the bottom. With flat_lvl predicate u can specify the desired level for flat a list.
Examples:
% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 2).
%
% ---> FlatLis = [e1, e2, e3, e4, e5, e6, e7, e8, e9]
% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 1).
%
% ---> FlatLis = [e1, e2, [e31, e32], e4, e5, e6, e7, e8, e9]
% Lis= [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]],
% flat_lvl(Lis, FlatLis, 0).
%
% ---> FlatLis = [[e1, e2, [e31, e32]], [e4, e5, e6, e7], [e8, e9]]
The predicate to flat a list with a specified level is the following, so just set DeepLvl to 1:
flat_lvl([],[],_).
flat_lvl([LisH| LisT], FlatLis, DeepLvl):-
Lvl is DeepLvl - 1, Lvl >= -1,
(flat_lvl(LisH, FlatH, Lvl); FlatH= [LisH]),
flat_lvl(LisT, FlatTail, DeepLvl),
append(FlatH, FlatTail, FlatLis), !.
?- flat_lvl(List, 1).
Ex: If I have been given two list [1,4,3,2,5,6] and [1,2,3] the final list should be [4,5,6].
i.e., Del([1,4,3,2,5,6], [1,2,3], Result).
----should output Result=[4,5,6].
I have tried something like this:
delete1(A, [A|B], B).
delete1(A, [B, C|D], [B|E]) :- delete1(A, [C|D], E).
But the output I'm getting is by deleting the element being passed as an parameter and not a list.
Output:
delete1(a,[a,b,c,d],Res).
(0) Call: delete1(a,[a,b,c,d],_h210) ?
(0) Exit: delete1(a,[a,b,c,d],[b,c,d]) ?
Res = [b,c,d]
Can anyone please help me how to go about this ?
Pure and simple: Use meta-predicate tfilter/3 in tandem with list_nonmember_t/3!
Like we did with memberd_t/3, we define list_nonmember_t/3 based on if_/3 and (=)/3:
list_nonmember_t([],_,true).
list_nonmember_t([E|Es],X,T) :-
if_(E=X, T=false, list_nonmember_t(Es,X,T)).
Let's put it together!
?- tfilter(list_nonmember_t([1,2,3]), [1,4,3,2,5,6], Xs).
Xs = [4,5,6]. % succeeds deterministically
del1([], _, []).
del1([A|L], B, R) :- member(A, B), del1(L, B, R).
del1([A|L], B, [A|R]) :- not(member(A,B)), del1(L, B, R).
So your delete1 is a good start, it allows to delete single element from the list, but it is not handling all of the cases. For example the lists that are not containing the element to be deleted.
So the right one would be :
delete1(_, [], []).
delete1(A, [A|B], B).
delete1(A, [C|B], [C|E]) :- delete1(A, B, E).
and then using this, you can define your del1 by applying delete1 recursively on the whole list:
del1([], _, []).
del1(L, [], L).
del1(L, [H|T], R) :-
delete1(H, L, R1),
del1(R1, T, R).
And of course you can use builtin list predicates as stated in the other answer.
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] .