I am having trouble writing code in Prolog which takes a list, removes all primes, and returns the rest of the list. I have written a prime checker predicate, prime/1, which works just fine, but when I apply my program to the list, as with almost anything I try to do in Prolog, I get back the list without the primes, as wanted, but in reverse order.
primemover(L, Lcomp):-
primeremover(L, [], Lcomp).
primeremover([], A, A).
primeremover([H | T], A, X):-
\+ prime(H),
primeremover(T, [H | A], X).
primeremover([H | T], A, X):-
prime(H),
primeremover(T, A, X).
I can see why the list comes back reversed by looking at my code, but I just can't find a way around it. If I try reversing the head and tail of the recursive case which moves the non-prime into the middle list, it works and comes out in the correct order, but with every value in its own nested list, which is even worse than coming out backwards.
Is there a simple way to correct this issue?
I think this fixes your problem:
primeremover([], []).
primeremover([H | T], [H | Y]):-
\+ prime(H),
primeremover(T, Y).
primeremover([H | T], Y):-
prime(H),
primeremover(T, Y).
I'm not sure if I am missing something, but I believe that you are approaching this as a functional language rather than a logical language. Also, the third argument doesn't really seem to add something to the solution; it can be removed without loss of functionality.
I don't have your prime predicate but I used this to test:
main :- primeremover([1,2,3,4,5], A), write(A).
prime(X) :- X = 2; X = 3; X = 5.
I used GNU Prolog (1.4.0).
You don't need to call an auxiliar function to do this, you can do it directly by using only the input variable and the return
Code:
primeremover([], []).
primeremover([H | T], Y):-
prime(H),
!,
primeremover(T, Y).
primeremover([H | T], [H | Y]):-
primeremover(T, Y).
You're using in your primeremover/3 predicate the second argument as an accumulator, i.e. an auxiliary argument that works as a stack, collecting intermediate results. This (useful) technique is often used in the definition of recursive predicates to get the benefits of tail recursion. A canonical example of this technique is the definition of a predicate for reversing a list. The naive definition is not tail recursive and thus requires space proportional to the length of the list:
reverse([], []).
reverse([Head| Tail], Reversed) :-
reverse(Tail, Reversed0),
append(Reversed0, [Head], Reversed).
Note that the recursive call in the second clause to the reverse/2 predicate is not the last call. Thus, the append/3 predicate call that follows must be suspended by saving it in a stack until the recursive reverse/2 predicate terminates. This stack grows one element per each recursive call. But this stack will not be required if the recursive call is the last call. The tail recursive definition can be coded using an accumulator:
reverse(List, Reversed) :-
reverse(List, [], Reversed).
reverse([], Reversed, Reversed).
reverse([Head| Tail], List, Reversed) :-
reverse(Tail, [Head| List], Reversed).
But, in your specific case, and as both Erwin and Guillermo explained, there's no need to use an accumulator as you can construct the output list as you traverse the input list. The code they suggested can be, however, arguably improved by avoiding testing if the current head of the input list is a prime twice (in the case of Erwin solution) and also by avoiding a cut (in case of the Guillermo solution) by using Prolog's standard if-then-else control construct:
prime_remover([], []).
prime_remover([Head| Tail], NonPrimes):-
( prime(Head) ->
prime_remover(Tail, NonPrimes)
; NonPrimes = [Head| NonPrimesTail),
prime_remover(Tail, NonPrimesTail)
).
Note that this version is (also) tail recursive.
Here is a minimal edit of your code to correct the issue.
%%// primeremover( +L, -Lcomp)
primeremover(L, Lcomp):- %// was:
primeremover(L, [], Lcomp).
primeremover([], A, A).
primeremover([H | T], A, [H | X]):- %// primeremover([H | T], A, X):-
\+ prime(H),
primeremover(T, A, X). %// primeremover(T, [H | A], X).
primeremover([H | T], A, X):-
prime(H),
primeremover(T, A, X).
Instead of prepending - adding at the front - elements to an accumulator, and returning its final value from the deepest invocation, we append - add at the end - elements to the return list, and set its final end pointer as [] at the deepest invocation. Both are essentially iterative processes, and both are compiled by Prolog as such, i.e. with constant control stack space use.
Both variants are tail recursive, but the new one is tail recursive modulo cons.
Because the variable A no longer serves as an accumulator, and is used instead as a final "pointer" (list's last cons cell), it is customary to call it Z instead.
The new code demonstrates the "difference list" technique: the logical variables A and X form a pair, describing a list's prefix from X to A as a "difference" between a list X and its tail A.
We thus get hold of the end value explicitly, in the interface call:
primeremover(L, Lcomp):-
primeremover(L, E, Lcomp), E = [].
We could use any value for E, as we need, not just the hard-coded [], by directly calling the primeremover/3 predicate.
This is actually more natural to code in Prolog, than the usual imperative "accumulator" technique (by cons, prepending), unless we actually need to build our result in reversed order. Although, appending elements to the end of open-ended list can just as rightfully be seen as accumulating.
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
Given the list as input (in the format mentioned below) , I need to get the output that is a simple list of lists, If the given input list is empty then the predicate should return an empty list,
Given the input
[[[a,b],[c]],[[d,e]],[[g,h],[j,k]],[[h,k,l,l]]]
I need to get the output
[[a,b],[c],[d,e],[g,h],[j,k],[h,k,l,l]]
I am having trouble performing recursion,
The code I tried is below,
function([],X):-append([],X,X).
function([Head|Tail],X):-
first(Tail,A),
append(Head,A,X),
removehead(Tail,C),
function(C,X).
where the predicates first returns first element of the list, removehead removes the first element of the list.
You make a fair attempt in the code you have shared. Here are the things that you need to improve:
The predicate name fucntion describes the fact that this predicate has one solution whenever the first argument is a list. This is typically done in the documentation, e.g. %! function(+Nested:list, -Denested:list) is det.
append([], X, X) is true by definition if X is a list, so it is superfluous here.
What are first/2, removehead/2? If you want to instantiate to the first element of a list, you can also write the clause head argument as [Head,A|C]. Then you also do not need to remove the head from Tail explicitly.
Once I make alterations based on the above I come up with the following code:
%! denest(+Nested:list, -Denested:list) is det.
denest([], []).
denest([H|T1], L):-
denest(T1, T2),
append(H, T2, L).
Example run:
?- denest([[[a,b],[c]],[[d,e]],[[g,h],[j,k]],[[h,k,l,l]]], L).
L = [[a, b], [c], [d, e], [g, h], [j, k], [h, k, l|...]].
Hope this helps!
I have a problem with my prolog code. I need to reverse all atomic elements of list.
Example: [1,2,[3,4]] -> [[4,3],2,1]
My solution:
myReverse([], []).
myReverse([H|T], X) :- myReverse(T, RT), myAppend(RT, H, X).
But it only gives me: [[3,4],2,1]
I think, I need to use is_list function and recursive call list if it's not atomic... but I am stuck... do you guys know how to write it?
Nearly. Consider this solution:
myReverse([], []) :- !.
myReverse([H|T], X) :-
!,
myReverse(H, NewH),
myReverse(T, NewT),
append(NewT, [NewH], X).
myReverse(X, X).
The first clause is the base case, which includes a cut (!) to exclude choices left because of the last clause.
The second clause reverses the head H, which may be an atom or a list. If H is an atom, the recursive subgoal after the cut evaluates with the last clause, and atoms are passed through unchanged. If H is a list, it is evaluated with the second clause and all elements are reversed. The next subgoal does the same with the remainder of the list (the tail, T), then are finally concatenated using the built-in append/3. Note that the new head element NewH is singular, so needs to be added to a singleton list structure as [NewH] as per the definition of append/3 which operates on lists.
The last clause passes all other things (i.e., atoms, numbers, etc. - anything that isn't a list or a variable) through unchanged.
revall(L, Y) :-
revall(L, [], Y).
revall([], Y, Y).
revall([H|T], T2, Y) :-
is_list(H),!,
revall(H, Hr),
revall(T, [Hr|T2], Y).
revall([H|T], T2, Y) :-
revall(T, [H|T2], Y).
here without append
I am trying to write a predicate that given the following list in Prolog:
[[1,a,b],[2,c,d],[[3,e,f],[4,g,h],[5,i,j]],[6,k,l]]
will produce the following list:
[[6,k,l],[[5,i,j],[4,g,h],[3,e,f]],[2,c,d],[1,a,b]]
As you can see I would like to preserve the order of the elements at the lowest level, to produce elements in the order 1, a, b and NOT b, a, 1.
I would also like to preserve the depth of the lists, that is, lists that are originally nested are returned as such, but in reverse order.
I have managed to achieve the desired order with the following code, but the depth is lost, i.e. lists are no longer nested correctly:
accRev([F,S,T],A,R) :- F \= [_|_], S \= [_|_], T \= [_|_],
accRev([],[[F,S,T]|A],R).
accRev([H|T],A,R) :- accRev(H,[],R1), accRev(T,[],R2), append(R2,R1,R).
accRev([],A,A).
rev(A,B) :- accRev(A,[],B).
I would appreciate help in correcting the code to preserve the correct nesting of lists. Thanks!
Two suggestions. First, here's one (rev_lists/2) which uses a bunch of SWI-PROLOG built-ins:
rev_lists(L, RL) :-
forall(member(M, L), is_list(M)), !,
maplist(rev_lists, L, L0),
reverse(L0, RL).
rev_lists(L, L).
This one works by testing if all elements of a list L are themselves lists (M); if so, it will recursively apply itself (via maplist) over all individual sub-lists, else it will return the same list. This has the required effect.
Secondly, here's rev_lists/2 again, but written such that it doesn't rely on built-ins except member/2 (which is common):
rev_lists(L, RL) :-
reversible_list(L), !,
rev_lists(L, [], RL).
rev_lists(L, L).
rev_lists([], Acc, Acc).
rev_lists([L|Ls], Acc, R) :-
( rev_lists(L, RL), !
; RL = L
),
rev_lists(Ls, [RL|Acc], R).
reversible_list(L) :-
is_a_list(L),
\+ (
member(M, L),
\+ is_a_list(M)
).
is_a_list([]).
is_a_list([_|_]).
It's basically the same strategy, but uses an accumulator to build up reverse lists at each level, iff they are comprised exclusively of lists; otherwise, the same list is returned.