Prolog recursing endlessly in getList predicate - list

This predicate is intended to tell if the list has the element in it and add it to a new list. However, once I finish recursing through and I have the correct list being returned, it recurses backwards until it ends up at the beginning again and then recurses through it again -- endlessly.
getList([],X,[]).
getList([H|T],Side,Others) :-
(length(T,3)),
(H == Side),
append([],[H],NewList),
getList(T,Side,NewList).
getList([H|T],Side,Others) :-
(H == Side),
append(Others, [Side], Others1),
getList(T,Side,Others1). // where it backwards recurses after finishing
getList([E],X,[]).
Please help me determine WHY it does this as well as find a solution.

If I understood your description of the predicate right it searches in the first list for the element(s) identical to the Element and copies the Element in the second list.
This predicate can be implemented as follows:
getList( Element, OldList, NewList ).
getList( Element, [], [] ).
getList( Element, [ X | Xs ], [ Element | Ys ]) :-
X == Element,
getList( Element, Xs, Ys ).
getList( Element, [ X | Xs ], Ys ) :-
% X \== Element,
getList( Element, Xs, Ys ).
The following query is succeded with the result NewList
?- getList( a(X), [ a(1), a(a), a(Y), a(X), b(Y), a(X) ], NewList ).
yes
NewList = [ a(X), a(X) ].
P.S. length( X, 3 ) will give you [ _ , _ , _ ] if X is an unbound variable.

Related

Understanding print at the end of list when removing duplicates

I've been trying to learn Prolog by writing a simple program that given a list of items, returns/stores a copy of the list without duplicates in the same order. Ex: [1,1,2,3,3,3,5] returns [1,2,3,5]. I'm using the append to add the numbers to an empty list and the member to check if the integer already has been added.
remove_duplicates([], R).
remove_duplicates([H|T], R) :-
member(H, R)
-> remove_duplicates(T, R)
; append(H, R),
remove_duplicates(T, R).
I've gotten the code to almost work, however when running the code it returns R = [1, 2, 3, 6|_].
I've tried tracing and debugging however I'm unable to understand why the |_ is added at the end.
My thought process for the code is as following, please point out if I'm misunderstanding something.
remove_duplicates([], R). % If first list is empty, return R. (Used to stop the recursion).
remove_duplicates([H|T], R) :-
member(H, R)
-> remove_duplicates(T, R) % If head is member of R (=true), call remove:_duplicates again without the head.
; append(H, R),
remove_duplicates(T, R). % else (if member(H, R) = false), add the head to list R and call remove_duplicates again with tail and R.
My answer to the question implement a prolog predicate that removes all duplicate elements as noted by #brebs is close, but it will not give you what you want. This
list_set( [] , [] ) .
list_set( [X|Xs] , Ys ) :- memberchk(X,Xs), !, list_set(Xs,Ys) .
list_set( [X|Xs] , [X|Ys] ) :- list_set(Xs,Ys) .
prefers the last of duplicated items, so
[1,2,3,3,2,1]
reduces to
[3,2,1]
Which violates the constraint in your problem statement, that you get
a copy of the list without duplicates in the same order.
We can switch that up to prefer the first of any duplicate elements by using a helper predicate with an accumulator and introducing the use of append/3:
list_set( Xs , Ys ) :- list_set( Xs , [] , Ys ) .
list_set( [] , Ys , Ys ) .
list_set( [X|Xs] , Ts , Ys ) :- memberchk(X,Ts) , ! , list_set(Xs,Ts,Ys) .
list_set( [X|Xs] , Ts , Ys ) :- append(Ts,[X],T1) , list_set(Xs,T1,Ys) .
This is fastest method I've found so far (doesn't use append or reverse):
https://stackoverflow.com/a/74024975/

Prolog write predicate that decrements all elements of a list of integers

as the title suggests, I have to write a predicate that decreases all the values of a list. I did this but I am not convinced can you help me?
decremento([ ],[ ]).
decremento([H | T], L):- decremento(T,N), L is N-1.
So the problem statement is to traverse a list of [presumably] numbers, decrementing each one?
So... something like this —
decremento( [] , [] ) . % the list is empty, nothing to decrement
decremento( [X|Xs] , [Y|Ys] ) :- % the list is non-empty, so...
Y is X-1, % - decrement the head of the list,
decremento(Xs,Ys) % - recurse down
. % Simple!
Running the above:
decremento( [1,2,3] , X ).
yields the desired
X = [0, 1, 2]
But... what about the other way?
decremento(X,[0,1,2]).
Sadly, that give us
Arguments are not sufficiently instantiated
In:
[2] 1 is _1632-1
[1] decremento([_1694|_1696],[1,2|...]) at line 3
We need to do a little type checking to be it work both ways. So, something like this will work properly.
decremento([1,2,3],X) yields X = [0,1,2]
decremento(X,[0,1,2]) yields X = [1,2,3]
decremento([1,2,3],[0,1,2]) yields true.
decremento( Xs, Ys ) :- nonvar(Xs), !, add_list(-1,Xs,Ys) .
decremento( Xs, Ys ) :- nonvar(Ys), !, add_list(+1,Ys,Xs).
add_list( _, [] , [] ) .
add_list( N, [X|Xs] , [Y|Ys] ) :- Y is X+N, add_list(N,Xs,Ys).
From the comment to another answer:
maplist(plus(-1), Xs, Ys)
?- maplist(plus(-1), [1,2,3], Ys).
Ys = [0, 1, 2].
?- maplist(plus(-1), Xs, [1,2,3]).
Xs = [2, 3, 4].
?- maplist(plus(-1), [1,X], [Y,2]).
X = 3,
Y = 0.

Finding an intersection in Prolog using list predicates

I'm really new to Prolog and I am trying to make an isIntersection that gives me the intersection of two lists and puts the answer in the third list. I cannot use any Prolog list predicates because it's for a class and that's just the rules. This is what I have and I'm having trouble debugging and seeing why this implementation is wrong. Anyone have any ideas?
/* Checks if the item is in the list */
in(Item, [Item|Rest]).
in(Item, [Not|Rest]) :- in(Item, Rest).
/* Makes the intersection list */
isIntersection([], [], []).
isIntersection([H|R], List, [H|Final]) :-
in(H, List),
isIntersection(R, List, Final),
write(H).
isIntersection([Discard|Rest], List, Final) :-
isIntersection(Rest, List, Final),
write(Discard).
Prolog is a very versatile query language, so let's use Prolog to find the problem!
?- isIntersection([a,b],[c,b],Zs).
false.
This failure is not what we expect. To better localize the problem we might a) generalize the query or b) reduce input size. I will try generalizing it first:
?- isIntersection([a,b],Ys,Zs).
loops. % ERROR: Out of global stack
Seems we have no luck, but then this query would have to produce infinitely many lists for Ys so it might be OK to loop.
I could continue that way, but why not let Prolog do the thinking for me? I will try all possible lists:
?- length(L,_),append(Xs,Ys,L), isIntersection(Xs,Ys,Zs).
L = Xs, Xs = Ys, Ys = Zs, Zs = []
; L = Xs, Xs = [_A], Ys = Zs, Zs = []
; L = Xs, Xs = [_A, _B], Ys = Zs, Zs = []
; L = Xs, Xs = [_A, _B, _C], Ys = Zs, Zs = []
; L = Xs, Xs = [_A, _B, _C, _D], Ys = Zs, Zs = []
; ... .
So for each list length (so far), there is only one solution with Ys and Zs being an empty list... Is there any solution for Ys being larger?
?- length(L,_),Ys = [_|_], append(Xs,Ys,L), isIntersection(Xs,Ys,Zs).
loops.
So lets take the minimal missing example from above with Ys having one element:
?- isIntersection([],[a],[]).
false.
With this goal, now look at your code!
But there is another problem (after fixing above):
?- isIntersection([a],[a],Xs).
Xs = [a]
; Xs = [].
The rule discards any element! But it should only discard those that are not in List. So:
isIntersection([Discard|Rest], List, Final) :-
list_without(List,Discard), % maplist(dif(Discard),List)
isIntersection(Rest, List, Final).
list_without([], _).
list_without([E|Es], F) :-
dif(E, F),
list_without(Es, F).
Finally, always keep an eye on negative examples. Many attempts here (incorrectly) succeeds for queries like isIntersection([a],[a],[]).
(Your relation in/2 might better be called element_in/2)
I'd go at it something like this, sorting and merging so as to avoid the O(n2) performance:
intersection_of( Xs , Ys , Zs ) :- % to find the intersection of two sets, we
sort(Xs,X1) , % - sort the left source list, removing duplicates to ensure that it's a set
sort(Ys,Y1) , % - sort the right source list, removing duplicates to ensure that it's a set
merge(Xs,Ys,Z1) , % - merge them to find the common members (an ordered set)
( var(Zs) -> % - if the result is unbound,
Zs = Z1 ; % - simply unify the merge result with the result set
sort(Zs,Z1) % - otherwise, sort the result and match against the merge result
) . %
The merge is simple
merge( [] , [] , [] ) .
merge( [_|_] , [] , [] ) .
merge( [] , [_|_] , [] ) .
merge( [X|Xs] , [Y|Ys] , [X|Zs] ) :- X = Y , merge( Xs , Ys , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs ) :- X #< Y , merge( Xs , [Y|Ys] , Zs ) .
merge( [X|Xs] , [Y|Ys] , Zs ) :- X #> Y , merge([X|Xs] , Ys , Zs ) .
there is only a List that can match your base case, and this simple fact inhibits the whole computation.

Prolog remove non-duplicates

I've been trying to write some code that takes a list of values, and removes all values which are only in the list once, the non-duplicates:
dbltaker([], []).
dbltaker([H | X], Y):-
\+mem(H, X),
dbltaker(X, Y).
dbltaker([H | X], [H | Y]):-
mem(H, X), !,
dbltaker(X, Y).
dbltaker([H | X], [H | Y]):-
mem(H, Y),
dbltaker(X, Y).
mem(H, [H | _]).
mem(H, [_ | T]):-
mem(H, T).
The trouble I've been having is that after I move a non-duplicate to the other list, it's duplicate is no longer a duplicate so isn't moved into the list. For example, the list [1, 1, 1, 2, 2, 3] gives [1, 1, 2] as the output, as the last one and two aren't considered duplicates as they're no longer members of their tails, and I can't check to see if they're members of the new list, as it's yet to be instantiated.
Is there a way around this?
Thanks.
I think the simpler way should be to should pass around to original list, to be able to check when an element is duplicate or not.
dbltaker(L, R) :- dbltaker(L, L, R).
dbltaker([], _L, []).
dbltaker([H|T], L, [H|R]) :- at_least_2(H, L), !, dbltaker(T, L, R).
dbltaker([_|T], L, R) :- dbltaker(T, L, R).
the service predicate at_least_2(H, L) can easily be implemented...
This is how I'd do it:
First, a check for list membership:
exists_in( A , [A|_] ) :- ! .
exists_in( A , [_|B] ) :- exists_in(A,B) .
Then a conditional add. If X is not contained in Y, add X to Y giving Z:
add_if_not_exists( X , Z , Z ) :- exists(X,T) , ! .
add_if_not_exists( X , Y , [X|Y] ) .
A worker predicate that does the hard work, using an accumulator (seeded to the empty list []) to build the set of distinct elements:
dedupe( [] , Z , Z ) . % if the source list is exhausted, we're done: the accumulator is the set of distinct list members.
dedupe( [X|Xs] , Y , Z ) :- % otherwise...
add_if_not_exists(X,Y,T) , % - add X to the accumulator if it's not already there.
dedupe(Xs,T,Z) % - and recurse down.
. % Easy!
And finally, the public interface predicate that simply invokes the worker predicate:
dedupe( Xs, Ys ) :- % dedupe a list
dedupe( Xs, [] , Ys ) % by invoking the helper predicate with the accumulator seeded with the empty set.
. %
Note: the worker predicate builds the deduped list in reverse order. If order is important, reversing a list is trivial:
rev( [] , [] ) .
rev( [X|Xs] , Rs ) :- rev( Xs , [X|Rs] ) .
Just modify the public interface to do the reversal:
dedupe1( Xs, Ys ) :- % dedupe a list
dedupe( Xs, [] , T ) , % by invoking the helper predicate with the accumulator seeded to the empty set.
rev(T,Ys) % and reversing the result.
. %

Prolog insert element after first occurrence

How I can add an element E right after the first occurrence of X in list Xs?
Example:
?- insert_right_behind(5,10,[2,4,10,12],Xs).
Xs = [2,4,10,5,12]. % expected answer
At this moment, I have problems understanding
the recursion that needs to be made since I am new to the language.
Thanks in advance!
In the previous answer most successful queries left behind useless choicepoints.
We can avoid these choicepoints by using if_/3 and (=)/3 like so:
item_following_in_inserted(I,J,[X|Xs],Ys0) :-
if_(J = X,
Ys0 = [J,I|Xs],
(Ys0 = [X|Ys], item_following_in_inserted(I,J,Xs,Ys))).
Let's run some queries!
?- item_following_in_inserted(5,10,[2,4,12],Xs).
false. % OK, unchanged
?- item_following_in_inserted(5,10,[2,4,10,12],Xs).
Xs = [2,4,10,5,12]. % succeeds deterministically
?- item_following_in_inserted(5,10,[2,4,10,12,10],Xs).
Xs = [2,4,10,5,12,10]. % succeeds deterministically
?- item_following_in_inserted(I,E,Xs,Ys).
Xs = [ E|_Z], Ys = [ E,I|_Z] % OK, unchanged
; Xs = [ _A,E|_Z], Ys = [ _A,E,I|_Z], dif(E,_A)
; Xs = [_A,_B,E|_Z], Ys = [_A,_B,E,I|_Z], dif(E,_A), dif(E,_B)
...
Use three predicate clauses:
% Inserting after in an empty list is an empty list:
insert_after( _X, _Y, [], [] ).
% If the "after" item is at the head of the list, then the "insert" item can go after it:
insert_after( X, Y, [Y|T], [Y,X|T] ).
% If the head of the list isn't the "after" item, then the result will be
% this with a new tail list that has the "insert" item inserted:
insert_after( X, Y, [H|T], [H|L] ) :-
Y \= H,
insert_after( X, Y, T, L ).
If the "after" item doesn't exist in the given list, then insert_after/4 will yield the original list. By removing the first insert_after clause above, it will just fail for that case.
Let's keep it simple and use append/3, meta-predicate maplist/2 and prolog-dif like so:
item_following_in_inserted(I,J,Xs,Ys) :-
append(Prefix,[J |Suffix],Xs),
maplist(dif(J),Prefix),
append(Prefix,[J,I|Suffix],Ys).
Done! It's query time... First, let's run the query the OP gave:
?- item_following_in_inserted(5,10,[2,4,10,12],Xs).
Xs = [2,4,10,5,12] % succeeds, but leaves behind choicepoint
; false.
What if the item is not a member of the given list?
?- item_following_in_inserted(5,10,[2,4, 12],Xs).
false. % fails, as expected: 10 is absent
Let's check that we only insert after the first occurrence—and nowhere else!
?- item_following_in_inserted(5,10,[2,4,10,12,10],Xs).
Xs = [2,4,10,5,12,10] % single solution
; false. % terminates universally
What about the most general query of item_following_in_inserted/4?
?- item_following_in_inserted(I,E,Xs,Ys).
Xs = [ E|_Z], Ys = [ E,I|_Z]
; Xs = [ _A,E|_Z], Ys = [ _A,E,I|_Z], dif(E,_A)
; Xs = [ _A,_B,E|_Z], Ys = [ _A,_B,E,I|_Z], dif(E,_A), dif(E,_B)
; Xs = [_A,_B,_C,E|_Z], Ys = [_A,_B,_C,E,I|_Z], dif(E,_A), dif(E,_B), dif(E,_C)
...