How prolog deals with this step-by-step? - prolog

I'm trying to understand prolog but I am stuck with one example, can you explain to me how is prolog going through this call:
eli(2,[2,2,1],L).
using those facts:
eli(X,[],[]).
eli(X,[Y],[Y]).
eli(X,[X,X|L],L1) :- eli(X,L,L1).
eli(X,[Y|L],[Y|L1]) :- eli(X,L,L1).
The results are:
L = [1]
L = [1]
L = [2, 2, 1]
L = [2, 2, 1]
and I'm not really sure why.
Thanks in advance!

It looks like your predicate is mean to delete two consecutive appearance of any element.
First clause, if the target list is empty, return the empty list. In this case the X variable in the fact is not necessary. Replace X by te anonymous variable.
eli(_,[],[]).
Second clause is similar to the first, but it matches the target list if it contains only one element. Variable X is also not necessary.
eli(_,[Y],[Y]).
Third clause, if the target list contains two or more elements, and in the Head of the list both elements are equal to X, don't copy this two elements to the Result list, and make a recursive call to the eli/3 predicate in the body of the rule, to continue the search.
eli(X,[X,X|L],L1) :- eli(X,L,L1), !.
In this case we add the cut predicate, to avoid backtracking after this rule succeeded. Otherwise you may get undesired results, like L = [2, 2, 1] in your test.
And the last clause, copy the element in the Head of the Target list to the Result list, and continue the recursive call, this will stop when the Target list is empty or contains only one element (your first two clauses).
eli(X,[Y|L],[Y|L1]) :- eli(X,L,L1).
Now this is your predicate eli/3:
eli(_,[],[]).
eli(_,[Y],[Y]).
eli(X,[X,X|L],L1) :- eli(X,L,L1), !.
eli(X,[Y|L],[Y|L1]) :- eli(X,L,L1).
Test:
?- eli(2,[2,2,1],L).
L = [1]
?- eli(2,[1,2,2,3],L).
L = [1, 3]

Related

Function to find a list in prolog

I am new to Prolog and I am trying to write a function that finds a list that follows some rules.
More specifically, given two numbers, N and K, I want my function to find a list with K powers of two that their sum is N. The list must not contain each power but the total sum of each power. For example if N=13 and K=5, I want my list to be [2,2,1] where the first 2 means two 4, the second 2 means two 2, and the third 1 means one 1 (4+4+2+2+1=13). Consider that beginning from the end of the list each position i represents the 2^i power of 2. So I wrote this code:
sum2(List, SUM, N) :-
List = [] -> N=SUM;
List = [H|T],
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
powers2(N,K,X):-
sum2(X,0,N),
sum_list(X, L),
K = L.
The problem is:
?- sum2([2,2,1],0,13).
true.
?- sum2([2,2,1],0,X).
X = 13.
?- sum2(X,0,13).
false.
?- powers2(X,5,[2,2,1]).
X = 13.
?- powers2(13,5,[2,2,1]).
true.
?- powers2(13,X,[2,2,1]).
X = 5.
?- powers2(13,5,X).
false.
In the cases, X represents the list I expected the output to be a list that follows the rules and not false. Could you help me to find how can I solve this and have a list for output in these cases?
The immediate reason for the failure of your predicate with an unbound list is due to your use of the -> construct for control flow.
Here is a simplified version of what you are trying to do, a small predicate for checking whether a list is empty or not:
empty_or_not(List, Answer) :-
( List = []
-> Answer = empty
; List = [H|T],
Answer = head_tail(H, T) ).
(Side note: The exact layout is a matter of taste, but you should always use parentheses to enclose code if you use the ; operator. I also urge you to never put ; at the end of a line but rather in a position where it really sticks out. Using ; is really an exceptional case in Prolog, and if it's formatted too similarly to ,, it can be hard to see that it's even there, and what parts of the clause it applies to.)
And this seems to work, right?
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
OK so far, but what if we call this with an unbound list?
?- empty_or_not(List, Answer).
List = [],
Answer = empty.
Suddenly only the empty list is accepted, although we know from above that non-empty lists are fine as well.
This is because -> cuts away any alternatives once it has found that its condition is satisfied. In the last example, List is a variable, so it is unifiable with []. The condition List = [] will succeed (binding List to []), and the alternative List = [H|T] will not be tried. It seems simple, but -> is really an advanced feature of Prolog. It should only be used by more experienced users who know that they really really will not need to explore alternatives.
The usual, and usually correct, way of implementing a disjunction in Prolog is to use separate clauses for the separate cases:
empty_or_not([], empty).
empty_or_not([H|T], head_tail(H, T)).
This now behaves logically:
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
?- empty_or_not(List, Answer).
List = [],
Answer = empty ;
List = [_2040|_2042],
Answer = head_tail(_2040, _2042).
And accordingly, your definition of sum2 should look more like this:
sum2([], SUM, N) :-
N = SUM.
sum2([H|T], SUM, N) :-
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
This is just a small step, however:
?- sum2(X, 0, 13).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] _2416 is 0+_2428* ...
ERROR: [8] sum2([_2462],0,13) at /home/gergo/sum.pl:5
ERROR: [7] <user>
You are trying to do arithmetic on H, which has no value. If you want to use "plain" Prolog arithmetic, you will need to enumerate appropriate values that H might have before you try to do arithmetic on it. Alternatively, you could use arithmetic constraints. See possible implementations of both at Arithmetics in Prolog, represent a number using powers of 2.

How to check certain elements in a list with anonymous variables

Imagine having a list like L = [1, 4, _, 5, _]
If I would want to check if 4 is a member of this list, I could do this with: member(4, L). This will return True, because there is a 4 in this list. However it returns true with every element I check, using member/2. This, of course, happens, because an anonymous variable can be matched with anything. So it will always return True. I was wondering if there would be a way I can remove all anonymous variables from list L. So a NewList would be [1, 4, 5].
Instead of removing variables from the list and then use member/2 you could also opt to implement your own predicate that describes a member/2-like relation for non-variable elements:
nonvarmember(X,[Y|_]) :-
nonvar(Y), % only try to unify with X if Y is not a variable
X=Y.
nonvarmember(X,[_Y|Ys]) :-
nonvarmember(X,Ys).
Now let's see how this predicate works:
?- nonvarmember(4,[1,4,_,5,_]).
true ;
false.
?- nonvarmember(4,[1,_,_,5,_]).
false.
?- nonvarmember(4,[1,4,_,5,_,Z]).
true ;
false.
However, the first argument still can be a variable:
?- nonvarmember(X,[1,4,_,5,_,Z]).
X = 1 ;
X = 4 ;
X = 5 ;
false.
?- nonvarmember(X,[_,_,_]).
false.
But be aware that it does not matter if you remove the variable elements from the list first and subsequently use member/2 or if you use nonvarmember/2, you run into the following problem: List-elements that are instantiated after you check for membership are not accounted for and hence might lead to unsound answers. The following example illustrates the problem:
?- A=4, nonvarmember(4,[A,B,C]).
A = 4 ;
false.
?- nonvarmember(4,[A,B,C]), A=4.
false.
In order to check if certain items are in a list that contains anonymous variables, you'd first need to (temporarily) remove all anonymous variables from that list. To do so you could use the built-in predicate subtract/3 and var/1.
subtract/3: the first element being the list you want to check, the second element being a list containing elements you want to remove from the list and the third element being the resulting list.
var/1: contains only one element (X) and returns True if X is an unbound variable.
In this case we want to subtract every element (X) that is returning True when var(X). In code, this is written as var(_).
Now we simply fill in the subtract/3 predicate like this: subtract(L, [var(_)], NewList).
NewList now only stores bound variables and member/2 will now work as intented.
In case of Swi-Prolog (at least) you can use include/3 and exclude/3 predicates to filter lists. You can use these predicates together with var/1 and nonvar/1, to remove variables from list.
In your particular case, checking whether 4 belongs to the list [1, 4, _, 5, _] could be done as follows:
L1 = [1, 4, _, 5, _],
exclude(var, L1, L2),
member(4, L2).

PROLOG defining 'delete' predicate

delete(X,[X|R],[_|R]).
delete(X,[F|R],[F|S]) :-
delete(X,R,S).
Above is my definition of delete predicate, for delete(X,L,R), intended to delete every occurrence of X in L with result R.
I had queried below, and get "G2397797". What does this string stand for?
?- delete(1,[1,2,3,4,5],X).
X = [_G2397797, 2, 3, 4, 5] .
If you simply correct your first clause and remove the unnecessary anonymous variable, you would get:
delete_each(X, [X|L], L).
delete_each(X, [Y|Ys], [Y|Zs]) :-
delete_each(X, Ys, Zs).
This will use unification, and delete each occurrence of X in the list upon backtracking:
?- delete_each(a, [a,b,a,c], R).
R = [b, a, c] ;
R = [a, b, c] ;
false.
Do you see how this is identical to select/3?
If you want to delete all occurrences of X in the list, you can see the answer by #coder.
In the answer you get X = [_G2397797, 2, 3, 4, 5] . , _G2397797 is not a string it is a variable that is not instantiated. This is due to the clause:
delete(X,[X|R],[_|R]).
which places in the output list an anonymous variable "_". You could write delete(X,[X|R],R).
But this has multiple problems. Firstly it only deletes the first occurrence of X not all because in the above clause when you find one you succeed. Also you haven't thought the case of empty list which is also the base case of the recursion. Finally in your second clause you haven't applied any rule that says F and X differ and this clause give wrong results when F equals to X.
So you could write:
delete(_,[],[]).
delete(X,[X|R],S):-delete(X,R,S).
delete(X,[F|R],[F|S]):-dif(X,F),delete(R,S).

Replace elements of a list with Prolog

how to replace any of the element in the list with prolog?
example:
replace(2,[1,2,3,2,1],5,X)
should have both the solutions:
X = [1,5,3,2,1]
X = [1,2,3,5,1]
You can do it by iterating over the input list:
%replace(_, [], _, []).
replace(Element, [Element|Tail], NElement, [NElement|Tail]).
replace(Element, [CurElement|Tail], NElement, [CurElement|NTail]):-
replace(Element, Tail, NElement, NTail).
Sample input:
?- replace(2,[1,2,3,2,1],5,X).
X = [1, 5, 3, 2, 1] ;
X = [1, 2, 3, 5, 1] ;
If you uncomment the first clause it would also output the solution where the output list remains unchanged.
The first clause (commented) is a base case for iterating over a list. It states that the replaced list of an empty list is the empty itself.
The second clause states that if the head of the list unifies with the Element then the replace list would contain the replaced element and the rest of the list (Tail).
The third clause is the recursive step, it takes the first element and calls recursively with the tail of the list, and the output is the element taken concatenated with the result of the recursive call.

Find a element in a sublist from a list at prolog

I have this
initialstate(0,[],[[1,0],[2,3],[1,2],[2,3]]).
I would like to find which sublist inside the list is the same with the number 1.
And after delete the sublist who had the number one.
It would be something like that :
?- initialstate(_,_,[X,_]), initialstate(_,_,list),
delete(list,X,Newlist),assertz(initialstate(A,B,Newlist)).
I know this is wrong but i am trying to explain you what i want to do.
I want my final list to be :
initialstate(0,[],[[2,3],[2,3]]).
Edit: A new answer to incorporate CapelliC's endorsement of delete/3 and OPs further queries in the comments.
Predicate:
initial_state_without_elements(initialstate(A,B,List), Element,
initialstate(A,B,FilteredList) ):-
delete(List, Element, FilteredList).
Query:
?- initial_state_without_elements(initialstate(0,[],[[1,0],[2,3],[1,2],[2,3]]), [2,_], NewState).
NewState = initialstate(0, [], [[1, 0], [1, 2]]).
We want to take some list of lists, ListOfLists, and remove all the sublists, Ls, that contain a given Element. In general, to check if an element X is in some list List, we we can use member(X, List).
So we want a list of lists, SubListsWithout, which contains all Ls of ListOfLists for which member(Element, SubList) is false.
Here is a predicate sublists_without_elements/3, which takes a list of lists, an element, and a variable as arguments, and unifies the variable with a list of the sublists of the first which do not contain the element. This predicate uses the standard recursive technique for describing lists:
sublists_without_element([], _, []).
sublists_without_element([L|Ls], Element, SubListsWithout) :-
member(Element, L), !,
sublists_without_element(Ls, Element, SubListsWithout).
sublists_without_element([L|Ls], Element, [L|SubListsWithout]) :-
sublists_without_element(Ls, Element, SubListsWithout).
The first clause is our base case: the empty list has no sublists, regardless of the element.
The second clause is true if (1) Element is a member of L, and (2) SubListsWithout is a list of the sublists of Ls which do not contain Element. (note: *L has not been added to SubListsWithout in this clause, which means it has been excluded from the lits we are accumulating. The ! is used to prune the search path here, because once we know that an Element is a member of L, we don't want to have anything to do with L again.)
The third clause is true if L is added to SubListsWithout, and SubListsWithout contains the rest of the sublists of Ls which do not have Element as a member.
The above is one way to write your own predicate to filter a list. It is important that you be able to write and read predicates of this form, because you will see tons of them. However, you'll also want to get to know the standard libraries of your Prolog implementation. In SWI-Prolg, you can simply use exclude\3 to accomplish the above task. Thus, you could achieve your desired goal in with the following:
filter_initial_state(initial_state(A,B,List),
Element,
initial_state(A,B,FilteredList)) :-
exclude(member(Element), List, FilteredList).
You can use it thus,
?- filter_initial_state(initial_state(0,[],[[1,0],[2,3],[1,2],[2,3]]), 1, Filtered).
and prolog will reply,
Filtered = initial_state(0, [], [[2, 3], [2, 3]]).
I think you've chosen the right builtin (delete/3), but there is some detail wrong. Here is a working 'query':
?- retract(initialstate(A,B,C)), C=[[X,_]|_], delete(C,[X,_],Newlist), assertz(initialstate(A,B,Newlist)).
A = 0,
B = [],
C = [[1, 0], [2, 3], [1, 2], [2, 3]],
X = 1,
Newlist = [[2, 3], [2, 3]].
First of all: if you do a assertz without first doing a retract you'll end with having an almost duplicate of your data, and probably is not what you want. assertz stores the updated initialstate after the old one (there is asserta, but I doubt will correct the bug).
Second, note how to use pattern matching to extract the essential information:
C=[[X,_]|_]
the use of _ (i.e. an anonymous var) is essential, because allows to specify which part of the complex structure we must ignore when using it. And we must use it also to indicate to delete/3 what to match.
delete(C,[X,_],Newlist)

Resources