prolog, list with proper brackets as result - prolog

I am wondering how to get a nice proper looking list with the elements I have! I've been trying to look up stuff on this but none of the actual examples I've found seem to actually work
Here is one method I found on the web:
create_list(Item, List, [Item|List]).
if I run this query:
Hi = [1,2], Hey = [3,4], create_list(Hi, Hey, Output).
The result gets weird:
Output = [[1,2], 3,4]
The brackets are all wrong!
It should be:
[[1,2], [3,4]]

The brackets are all wrong! It should be:
[[1,2], [3,4]]
This is because your create_list uses [Item|List]. If you wanted brackets around [3,4] to remain in place, replace [Item|List] with [Item,List]. Of course List has incorrect meaning now, so I would rename it, as follows:
list_of_two(First, Last, [First, Last]).
This would not work for more than two items, however. Your original one rule would work, like this:
create_list([1,2],[],O1), create_list([3,4],O1,O2), create_list([5,6],O2,O3).
This produces
[[5, 6], [3, 4], [1, 2]]
in the O3 list.

In contrast with other languages, a list is a very basic datastructure in Prolog:
[] is/creates an empty list
[1] is/creates a list with a single element
[1,2,3,4,....,n] is/creates a list with n elements
[1|[2,3,4]] is/creates a list by inserting 1 in the list [2,3,4] (the result is [1,2,3,4])
So, you don't need a predicate to "create" a list: if you have n elements just put them in brackets; if the elements are generated recursively, use | to create a list with the new element. For example:
put_in_list(A1,A2,A3, L):- L = [A1,A2,A3].
alternatively:
put_in_list(A1,A2,A3, [A1,A2,A3]).
also:
generate(0, []).
generate(N, [ [N, NN]| Rest ]):-
NN is N-1,
NNN is N-2,
generate(NNN, Rest).
All in all, you should be careful with types; in your case, you have a list of numbers (let's call it X) and you want a list of lists of numbers (so this would be a list of Xs). The problem was created when you gave a list of Xs as an argument instead of an X to a predicate.

Related

Merging 2 lists into a third but in pairs

I want, given 2 lists, to merge them into a third one but each element of the third list is a list of the first and second list's elements.
E.g. given the list1 [1,2,3] and list2 [1,2,3] I want the final list to be [[1,1],[2,2],[3,3]]
What I've done so far is
merge([],[],Z).
merge([H1|T1],[T2|T2],Z):-
append([H1],[H2],W),merge(T1,T2,[W,Z]).
but I get a False result. Why isn't it working?
There are some flaws in your code:
when the first two lists are empty, the result must be an empty list too;
Instead of [T2|T2] you should write [H2|T2] to represent the second list;
there is no need to use append([H1],[H2],W) to create a list with two elements, just write [H1,H2];
since the recursive call must merge the tails of the first and second lists, there is no way the result of this call to be a list starting with the element [H1,H2].
Thus, a correct definition for that predicate is as follows:
my_merge([], [], []).
my_merge([H1|T1], [H2|T2], [[H1,H2]|T3]):-
my_merge(T1, T2, T3).
Examples:
?- my_merge([a,b,c], [1,2,3], L3).
L3 = [[a, 1], [b, 2], [c, 3]].
?- my_merge(L1, L2, [[1,a],[2,b],[3,c]]).
L1 = [1, 2, 3],
L2 = [a, b, c].
Remark Consider the possibility of representing the pair [H1,H2] as H1-H2, as the latter representation is more commonly used in Prolog.

How to concatenate 3 lists in Prolog without using append

I know how to concatenate 2 lists without append but how would you go about concatenating 3 lists without append.
You could foldl your catenate function over a list of lists.
list_list_catenate([E], L, [E|L]). %// [4] cat [a,b,c] is [4,a,b,c]
list_list_catenate([H|T], L, Cat) :- %// [4,5] cat [a,b,c] is [4|(5 cat [a,b,c])]
list_list_catenate(T, L, TCat),
Cat = [H|TCat].
Lists = [[1,2,3], [4,5,6], [7,8,9]],
reverse(Lists, RevLists),
foldl(list_list_catenate, RevLists, [], Result).
Fold left is a loop structure common in functional programming languages, it pushes each of the list items into the helper, along with the result of the previous time, so they aggregate up.
And this needs a reverse because of the way foldl maps the arguments to the helper; without that, it goes [1,2,3], [] then [4,5,6], [1,2,3] then [7,8,9], [4,5,6,1,2,3].

How prolog deals with this step-by-step?

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]

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)

Prolog flatten list

flatten([A|B],R):- (islist(A)->(flatten(A,R1),R=R1);(write(A),append([A],R1,R))), flatten(B,R1).
flatten(X,X).
islist([_|_]).
This is the code i written but i have strange problem..
I get
257 ?- flatten([1,[],2,[3],[3,[3,5]]],R).
1[]23335335
R = [1, [], 2, [3], [3, [3, 5]]] .
Although the numbers from write are not list they are appended as list:S...
There are some errors in your definition of flatten/2:
Your first clause will fail because if A is a list it will first instantiate R1 with R and then you try to unify it again with flatten(B, R1).
flatten(X,X). -> This clause leaves the list 'as is' without any flattening.
Check this other implementation:
flatten(List, Flattened):-
flatten(List, [], Flattened).
flatten([], Flattened, Flattened).
flatten([Item|Tail], L, Flattened):-
flatten(Item, L1, Flattened),
flatten(Tail, L, L1).
flatten(Item, Flattened, [Item|Flattened]):-
\+ is_list(Item).
Here we use two predicates: flatten/2 and flatten/3. The 'work' will be done in flatten/3 where the second argument will hold the intermediate flattened list.
The first clause is the base case: when we reach the empty list we are done so we instantiate the third argument with the intermediate flattened list.
The second clause deals with recursion. It flattens the first item in the list (whether it is an item or a sublist), and proceeds with the rest of the input list.
The last clause is the 'base case' for the non-lists items. It prepends the item at the beginning of the intermediate flattened list, but it only does this for items which are not lists as that case was taken care in the second clause.

Resources