Prolog delete an element into a given list - prolog

Hello I wish some advice or words about this task:
Define a statement with three parameters where the first one is a list, the second one is an element (atom or list) and the last one is a list which must accomplish it is equal to the first but first's list' elements which match second parameter,are gone.
Examples:
> elimina([f, e, d, [a, h], a, d, a], a, L)
L = [f, e, d, [a, h], d]
> elimina([f, e, d, [ a, h], a, [d, a]], [a, h], L)
L = [f, e, d, a, [d, a]]
I tried:
elimina([],_,[]).
elimina([X],X,[]).
elimina([X],Y,[X]).
elimina([H|T],H,Result) :-
elimina([T],H,Result).
elimina([H|T],Y,Result):-
elimina([T],H,Result).
I have the doubt about what to write when I shout the recursive call:
elimina([T],H,Result).
Because first I don't know how differently should be the behave when the input second element matchs the head rather than don't matching the head; so I put the same call.
Also I doubt because: Is really needed to put the base case: elimina([X],Y,[X]).? I thought we could pass the exercise with just matching the element to delete with the ones which are really into the list.
Thank you for your time.

There is a very general method how you can test your own code in Prolog. Simply ask Prolog to generate via the most general question all possibilities.
?- elimina([], D, Ys).
Ys = []. % 1: nice!
?- elimina([X], D, Ys).
D = X, Ys = [] % 1: nice!
; Ys = [X] % 2: lacks dif(X, D)
; X = [], D = [], Ys = [] % 3: correct but subsumed by 1
; D = X, Ys = [[]] % 4: incorrect
; X = [], D = [], Ys = [] % 5: correct but subsumed by 1
; X = [], D = [], Ys = [[]] % 6: incorrect
; X = [], D = [], Ys = [] % 7: correct but subsumed by 1
; ... .
For the empty list everything is fine. But for the one-element list, there are many superfluous answers! Actually, there should only be two answers:
D = X, Ys = []
; dif(D, X), Ys = [X].
So now pick some case you want to improve!
Maybe take answer #4 and set D = a, X = a:
?- elimina([a], a, Ys).
Ys = [] % 1: nice
; Ys = [a] % 2: incorrect
; Ys = [[]] % 3: incorrect
; Ys = [] % 4: correct but subsumed by 1
; Ys = [[]] % 5: incorrect and subsumed by 3
; Ys = [] % 6: correct but subsumed by 1
; ... .
So I will pick #3 which actually should fail, but does not
?- elimina([a],a,[[]]).
true
; true
; ... .
Narrow down the culprit by inserting false and some extra equations:
?- elimina([a],a,[[]]).
false.
elimina([],_,[]) :- false.
elimina([X],X,[]) :- false.
elimina([X],Y,[X]) :- Y = a, X = [].
elimina([H|T],H,Result) :- false,
elimina([T],H,Result).
elimina([H|T],Y,Result):- Result = [[]],
elimina([T],H,Result).
Now look at what is left and think about it. Should these remaining rules really hold?
In the remaining visible part there must be an error!

When describing lists, it's usually worthwhile to consider using DCGs for the task. You could describe the relation like so:
elimina(L1,X,L2) :- % L2 is described by
phrase(elimina_x(L1,X),L2). % elimina_x//2
elimina_x([],_X) --> % nothing to delete
[]. % from the empty list
elimina_x([X|Xs],X) --> % if the head of the list equals X
elimina_x(Xs,X). % it's not in the list, same for the tail
elimina_x([X|Xs],Y) --> % if the head of the list
{dif(X,Y)}, % differs from Y
[X], % it is in the list
elimina_x(Xs,Y). % same for the tail
Your example queries yield the desired result.
?- elimina([f, e, d, [a, h], a, d, a], a, L).
L = [f,e,d,[a,h],d] ? ;
no
?- elimina([f, e, d, [ a, h], a, [d, a]], [a, h], L).
L = [f,e,d,a,[d,a]] ? ;
no
Alternatively, you can also express this relation more compactly, using if_/3, (=)/3 and tfilter/3:
dif_t(X,Y,T) :-
if_(X=Y,T=false,T=true).
elimina(L1,X,L2) :-
tfilter(dif_t(X),L1,L2).
The above queries yield the same answers with this version.

Related

Why are solutions in the wrong order?

I have been asked to
define a predicate subseq/2, with signature subseq(-,+),
which is true when both its arguments are lists, and its first
argument can be constructed by removing zero or more elements
from its second argument.
... with intended solution order:
?- subseq(X, [a, b, c]).
X = [a, b, c] ;
X = [a, b] ;
X = [a, c] ;
X = [a] ;
X = [b, c] ;
X = [b] ;
X = [c] ;
X = [].
My code:
subseq([], []).
subseq([], [_|_]).
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
My code's solution order:
?- subseq(X, [a, b, c]).
X = []
X = [a]
X = [a, b]
X = [a, b, c]
X = [a, c]
X = [b]
X = [b, c]
X = [c] ;
false.
How do I achieve the intended solution order?
In Prolog, the order of the rules is crucial. To get the desired output, simply change the order of the rules, like this:
subseq([X|XS], [X|YS]) :- subseq(XS, YS).
subseq([X|XS], [_|YS]) :- subseq([X|XS], YS).
subseq([], []).
subseq([], [_|_]).
?- subseq(X,[a,b,c]).
X = [a, b, c]
X = [a, b]
X = [a, c]
X = [a]
X = [b, c]
X = [b]
X = [c]
X = []
Little tweaks can change the order:
sub_list_forwards(Sub, Long) :-
sub_list_forwards_(Long, Sub).
sub_list_forwards_([], []).
% Either pick H, or don't
sub_list_forwards_([H|T], S) :-
(S = Sub ; S = [H|Sub]),
sub_list_forwards_(T, Sub).
Result in swi-prolog:
?- sub_list_forwards(S, [a,b,c]).
S = [] ;
S = [c] ;
S = [b] ;
S = [b, c] ;
S = [a] ;
S = [a, c] ;
S = [a, b] ;
S = [a, b, c].
Or tweak the selection line to be:
(S = [H|Sub] ; S = Sub),
... which results in the order you were given:
?- sub_list_forwards(S, [a,b,c]).
S = [a, b, c] ;
S = [a, b] ;
S = [a, c] ;
S = [a] ;
S = [b, c] ;
S = [b] ;
S = [c] ;
S = [].
Note that neither of these leave an unwanted choicepoint at the end, because they use first-argument indexing on [] vs [H|T] with 1 selection each.
Does the order matter? What would be an optimum order? It probably varies.
In general it is best to put the base case (i.e. [], []) first, for flexibility (and because they sometimes contain a cut).
This is programming, rather than mathematics, so meaningful variable names/initials are far better for readability than using the likes of X and Y continually.
Using (S = [H|Sub] ; S = Sub), produces the sensible:
?- nth1(5, L, e), sub_list_forwards([a,b,c], L).
L = [a, b, c, _, e] ;
L = [a, b, c, _, e, _] ;
L = [a, b, c, _, e, _, _] ;
L = [a, b, c, _, e, _, _, _] ;
... rather than a stack overflow, and so is preferable.

define a predicate solution/3 which is true when its three arguments, all lists, has the third list containing all elements of the first two arguments

solution([ ], List, List).
solution([Head|Tail], List,[Head|Result]):-
solution(Tail, List,Result).
expected output
| ?- Solution(X,Y,[a,b,c]).
X = [a,b,c]
Y = [] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,c]
Y = [b] ? ;
X = [a]
Y = [b,c] ? ;
X = [b,c]
Y = [a] ? ;
X = [b]
Y = [a,c] ? ;
X = [c]
Y = [a,b] ? ;
X = []
Y = [a,b,c] ? ;
actual output
X = []
Y = [a,b,c] ? ;
X = [a]
Y = [b,c] ? ;
X = [a,b]
Y = [c] ? ;
X = [a,b,c]
Y = [] ? ;
It is not going through all the possible solutions that can be made from the predicate defined. i am expecting the output to be as shown above containing all the solutions of combining 2 lists together
Any help?
Your predicate is missing some clauses. The first clause says that if the first list is exhausted, then the result is the second list.
The second clause specifies that if the first list is not exhausted, we simply take the first element of that list as a result. This thus means that you basically implemented an append/3 predicate [swi-doc].
Based on your sample output, there is however a decision whether to take from the first list, or the second list. We thus should implement a clause like:
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
If both lists are exhausted, we can return an empty list, so we can define a base-clause like:
solution([], [], []).
and thus obtain as full solution:
solution([], [], []).
solution([H1|T1], L2, [H1|R]) :-
solution(T1, L2, R).
solution(L1, [H1|T2], [H1|R]) :-
solution(L1, T2, R).
This then gives us:
?- solution(X,Y,[a,b,c]).
X = [a, b, c],
Y = [] ;
X = [a, b],
Y = [c] ;
X = [a, c],
Y = [b] ;
X = [a],
Y = [b, c] ;
X = [b, c],
Y = [a] ;
X = [b],
Y = [a, c] ;
X = [c],
Y = [a, b] ;
X = [],
Y = [a, b, c].

Prolog: eliminate repetitions in query

I've been trying to write a simple code, that would behave in this manner:
| ?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? ;
X = [a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
And
| ?- hasCoppiesOf([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = ...
This desire resulted in next piece of code:
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B).
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
And it gives me what I want on the second query, however, the first results in:
?- hasCoppiesOf(X,[a,b,a,b,a,b,a,b]).
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
X = [a, b, a, b, a, b] ;
It seems to be working fine, but that repetition of the same answers bothers me. It's, probably, a simple mistake, but is there a way to make the output prettier?
And honestly, that a mystery, why Prolog treats two identical arrays as different answers.
Or maybe it's just something wrong with my system?
Edit:
The gentle guidance of the person in the comments helped me to solve this issue. However, if this question will be reading the person who wants to solve exactly the same problem - code not really working well, my apologies.
I think you just made your predicate more complex than it needs to be, probably just overthinking it. A given solution may succeed in multiple paths through the logic.
You can do this without append/3 by aligning the front end of the lists and keep the original list to "reset" on repeats:
% Empty list base cases
dups_list([], []).
dups_list([_|_], []).
% Main predicate, calling aux predicate
dups_list(L, Ls) :-
dups_list(L, L, Ls).
% Recursive auxiliary predicate
dups_list([], [_|_], []).
dups_list([], [X|Xs], [X|Ls]) :-
dups_list(Xs, [X|Xs], Ls).
dups_list([X|Xs], L, [X|Ls]) :-
dups_list(Xs, L, Ls).
Here are some results:
| ?- dups_list(X,[a,b,a,b,a,b,a,b]).
X = [a,b] ? a
X = [a,b,a,b]
X = [a,b,a,b,a,b,a,b]
no
| ?- dups_list([a,b,a,b,a,b,a,b], X).
X = [] ? ;
X = [a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ? ;
X = [a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b,a,b] ?
...
| ?- dups_list(A, B).
A = []
B = [] ? ;
A = [_|_]
B = [] ? ;
A = [C]
B = [C] ? ;
A = [C]
B = [C,C] ? ;
A = [C,D]
B = [C,D] ? ;
A = [C]
B = [C,C,C] ? ;
A = [C,D,E]
B = [C,D,E] ? ;
...
There may be a way to simplify the solution just a bit more, but I haven't played with it enough to determine if that's the case.
I think this is what you're trying for...
coppies(Z,Z,[]).
coppies(X,Z,[Y|Ys]):- \+member(Y,Z),coppies(X,[Y|Z],Ys).
coppies(X,Z,[Y|Ys]):- member(Y,Z),coppies(X,Z,Ys).
copies(M,[Y|Ys]):-coppies(M,[],[Y|Ys]).
Input:
copies(X,[1,2,1,2,1,2]).
Output:
X = [2, 1].
BTW I've used some different names instead..
Okay, I got your problem, you want to eliminate the repetitions.
hasCoppiesOf(A,[]).
hasCoppiesOf([H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf([H1|T1], X, T2).
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!. %Change here, place a cut after the termination.
hasCoppiesOf(A, [H1|T1], [H1|T2]) :-
append(T1, [H1], X),
hasCoppiesOf(A, X, T2).
This is the change that you need to make.
hasCoppiesOf(A, A, B) :-
hasCoppiesOf(A, B),!.
A Cut '!' terminates the unwanted backtracking and thereby repetitions.

Filter list in prolog

I'm trying to rewrite code from Haskell to Prolog.
count :: Eq a => a -> [a] -> Int
count x = length . filter (x==)
f :: [Integer] -> [Integer]
f [] = []
f list = filter (\x -> count x list == 1) list
This code return list that contains elements that appears only once in the list.
So if I have list [1,1,2,2,3,4,4,5] this function returns [3,5]
I tried to find filter construction in Prolog but seems there no such thing. How can I make similar function in Prolog ?
To the existing answers, I would like to add an answer that is quite general in the sense that you can use it in multiple directions.
Building block: list_element_number/3
I start with the following predicate, defining a relation between:
a list Ls0
an element E
the number N of occurrences of E in Ls0
Here it is:
list_element_number(Ls0, E, N) :-
tfilter(=(E), Ls0, Ls),
length(Ls, N).
This solution uses tfilter/3 from library(reif). The predicate subsumes the function count you have posted. The main benefit of this predicate over the function is that the predicate can be used not only in those cases that even Haskell can do easily, such as:
?- list_element_number([a,b,c], a, N).
N = 1.
No, we can use it also in other directions, such as:
?- list_element_number([a,b,c], X, 1).
X = a ;
X = b ;
X = c ;
false.
Or even:
?- list_element_number([a,b,E], X, 2).
E = X, X = a ;
E = X, X = b ;
false.
Or even:
?- list_element_number([A,B,C], X, 3).
A = B, B = C, C = X ;
false.
And even in the most general case, in which all arguments are fresh variables:
?- list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [E, E],
N = 2 ;
Ls = [E, E, E],
N = 3 .
We can fairly enumerate all answers like this:
?- length(Ls, _), list_element_number(Ls, E, N).
Ls = [],
N = 0 ;
Ls = [E],
N = 1 ;
Ls = [_160],
N = 0,
dif(E, _160) ;
Ls = [E, E],
N = 2 .
Main predicate: list_singletons/2
Using this building block, we can define list_singletons/2 as follows:
list_singletons(Ls, Singles) :-
tfilter(count_one(Ls), Ls, Singles).
count_one(Ls, E, T) :-
list_element_number(Ls, E, Num),
cond_t(Num=1, true, T).
This uses cond_t/3 and (again) tfilter/3 from library(reif).
Sample queries
Here are a few sample queries. First, the test case you have posted:
?- list_singletons([1,1,2,2,3,4,4,5], Singles).
Singles = [3, 5].
It works as desired.
Now a case involving variables:
?- list_singletons([A,B], Singles).
A = B,
Singles = [] ;
Singles = [A, B],
dif(A, B).
On backtracking, all possibilities are generated: Either A = B holds, and in that case, there is no element that occurs only once. Or A is different from B, and in that case both A and B occur exactly once.
As a special case of the above query, we can post:
?- list_singletons([A,A], Singles).
Singles = [].
And as a generalization, we can post:
?- length(Ls, _), list_singletons(Ls, Singles).
Ls = Singles, Singles = [] ;
Ls = Singles, Singles = [_7216] ;
Ls = [_7216, _7216],
Singles = [] ;
Ls = Singles, Singles = [_7828, _7834],
dif(_7828, _7834) ;
Ls = [_7216, _7216, _7216],
Singles = [] ;
Ls = [_7910, _7910, _7922],
Singles = [_7922],
dif(_7910, _7922) .
Enjoy the generality of this relation, obtained via logical-purity.
A more simple version :
filter_list(L,OutList):-findall(X, (select(X,L, L1),\+member(X, L1)) , OutList).
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
Without findall, you can try
filter_list(In, Out) :- filter_list(In, _, Out).
filter_list([], [], []).
filter_list([H|T], L1, L2) :-
filter_list(T, LL1, LL2),
( member(H, LL1)
-> L1 = LL1, L2 = LL2
; (select(H, LL2, L2)
-> L1 = [H|LL1]
; L1 = LL1, L2 = [H|LL2])).
without counting...
filter_uniques([],[]).
filter_uniques([H|T],F) :-
delete(T,H,D),
( D=T -> F=[H|R],S=T ; F=R,S=D ),
filter_uniques(S,R).
a more direct rewrite of your code, with library(yall) support for inlining of the filter predicate (the first argument to include/3)
filt_uniq(L,F) :-
include({L}/[E]>>aggregate(count,member(E,L),1),L,F).
A simple version:
(see the comment by #false below, the version with findall/3 has some inconsistency problems in more complex queries but second version looks ok however it is definitely not so efficient ).
filter_list(L,OutList):-findall(X, (member(X,L),count(X,L,N),N=:=1) , OutList).
count(_,[],0).
count(X,[X|T],N):-count(X,T,N1),N is N1+1.
count(X,[X1|T],N):-dif(X,X1),count(X,T,N).
The predicate filter_list/2 uses findall/3 and simply states find all X that belong to the list L and count returns 1 and store them in OutList.
Example:
?- filter_list([1,1,2,2,3,4,4,5],L).
L = [3, 5].
You could write filter_list/2 without using findall/3 like:
filter_list(L,OutList):- filter_list(L,OutList,L).
filter_list([],[],_).
filter_list([H|T],[H|T1],L):-count(H,L,N), N=:=1, filter_list(T,T1,L).
filter_list([H|T],T1,L):-count(H,L,N), N > 1, filter_list(T,T1,L).

Some doubts about how work this particular query of a delete from a list predicate

I have a doubt about how work this query for this del/3 predicate:
/* BASE CASE: If I delete X from List and X is the HEAD of List, NewList is
the Tail of List
*/
del(X, [X|Tail], Tail).
/* GENERAL CASE: If the head of List is not X then the program have to delete
X in the Tail of List
*/
del(X, [Y|Tail], [Y|Tail1]) :- del(X, Tail, Tail1).
The predicate logic is very simple: delete X item form a list creating a new list without X: if X is in the head of the list the newlist is its tail. Otherwise, if the X item is not in the head of the list, try to find it (and delete) in the Tail creating a new tail Tail1.
Ok, so I have no problem with the predicate logic but I am having some problem trying to understand how work this query (I have to use it in another program):
del([Top1|Stack1], [[a,b,c],[],[]], Stacks1).
So this query have to delete [Top1|Stack1] from [[a,b,c],[],[]] that is a list of stacks (in this particular case I have 3 stacks: [a,b,c] and 2 empty stacks: []) generating so a new list of stacks named Stacks1
If I try to execute a trace of the query I obtain this:
[trace] ?- del([Top1|Stack1], [[a,b,c],[],[]], Stacks1).
Call: (7) del([_G389|_G390], [[a, b, c], [], []], _G412) ? creep
Exit: (7) del([a, b, c], [[a, b, c], [], []], [[], []]) ? creep
Top1 = a,
Stack1 = [b, c],
Stacks1 = [[], []] .
I have some difficulties to understand why: [Top1|Stack1] is unified with the first stack [a, b, c]
EDIT:
I think that maybe work in this way: The list of Stacks is: [[a,b,c],[],[]] that is a list of lists wherein the first list is: [a,b,c] (that is the head of this list of list**
So when I write: [Top1|Stack1] happens that:
Top1 = [a,b,c]
*Stack1 = [[],[]]*
So happens that Top1 is the first stack in the stacks list and Stack1 is the list of others stacks.
So when I write the predicate:
del([Top1|Stack1], Stacks, Stacks1).
(where, for example: Stacks = [[a,b,c],[],[]])
It work in this way:
It unifiest Top1 with the first stack in stack list: [a,b,c] and delete it from Stacks list...
My dount is related on Prolog semantic viz when I execute a simple query as:
del(b, [a,b,c], NewList).
it delete b item from the list and NewList=[a,c]
but when I have that the field of the item that have be delete is something like: [Head|Tail] is it the Head item that have be to deleted?
The query D=[[a,b,c],[],[]], del([A|B], D, C) picks any list matching [A|B] from among D's elements. The only possibility here is [A|B]=[a,b,c] and the leftovers are C=[[],[]].
In general del fully backtracks, finding all possibilities one by one. Here there is only one possibility.
To better understand del, try this:
2 ?- del(X,[A,B,C],D).
X = A,
D = [B, C] ;
X = B,
D = [A, C] ;
X = C,
D = [A, B] ;
false.
It isn't trying to "find" X; it's just picking it one by one from among the possibilities (the 2nd argument). That's what the predicate says that it is / does.
Of course if the lists are instantiated to ground terms, some might not match and will be rejected, creating an impression of a value being searched for:
4 ?- del(b, [a,b,c,d], R).
R = [a, c, d] ;
false.
5 ?- del(b, [a,b,X,d], R).
R = [a, X, d] ;
X = b,
R = [a, b, d] ;
false.
The term [A|B] just matches any non-empty list (or a logical variable):
6 ?- del([A|B], [[a],b,X,d], R).
A = a,
B = [],
R = [b, X, d] ;
X = [A|B],
R = [[a], b, d] ;
false.
7 ?- del([A|B], [[a],b,[],d], R).
A = a,
B = [],
R = [b, [], d] ;
false.
So e.g. del([A|B], [[1,2,3], [4,5], [], [6]], R) will pick any non-empty list from the 4 lists given in the 2nd argument of this sample call, and while it does that, it will bind A to the head element and B to the rest of elements of the list that was picked.
This predicate is known as select/3 in the wild. :)
Illustration:
del(X, [X|Tail], Tail).
X X
--------------------
T T
a a
i i
l l
del(X, [Y|Tail], [Y|Tail1]) :- del(X, Tail, Tail1).
Y Y
--------------------
T T
/ . a
X - . i
\ . l
. 1
l

Resources