How to perform long concatenation of lists in Prolog? - list

I am interested in performing a long concatenation of lists, using Prolog language.
The objective is to define a predicate that gets an unknown number of lists, and concatenates them all into one list (that is given as the second argument to the predicate).
I know I should first understand how Prolog supports arguments with unbounded size, but I think the answer to that is using lists, for example:
[a | [[b,c,d] | [[e,f,g] | [h,i,j,k]]]].
If so, I thought about writing the predicate somewhat like this:
l_conc([ ],[ ]).
l_conc([[ ]|Tail],L):-
l_conc(Tail,L).
l_conc([[Head|L1]|Tail],[Head|L2]):-
l_conc([L1|Tail],L2).
However, it only concatenates empty lists to one another.
Please help me here (both regarding the arguments representation and the predicate itself) :-) Thanks!

Before I answer the actual question, I have a couple of comments.
First, the term you give as an example [a | [[b,c,d] | [[e,f,g] | [h,i,j,k]]]] can be written more compactly in Prolog. You can use the Prolog toplevel itself to see what this term actually is:
?- Ls = [a | [[b,c,d] | [[e,f,g] | [h,i,j,k]]]].
Ls = [a, [b, c, d], [e, f, g], h, i, j, k].
From this, you see that this is just a list. However, it is not a list of lists, because the atoms a, h, i etc. are not lists.
Therefore, your example does not match your question. There are ways to "flatten" lists, but I can only recommend against flattening because it is not a pure relation. The reason is that [X] is considered a "flat" list, but X = [a,b,c] makes [[a,b,c]] not flat, so you will run into logical inconsistencies if you use flatten/2.
What I recommend instead is append/2. The easiest way to implement it is to use a DCG (dcg). Consider for example:
together([]) --> [].
together([Ls|Lss]) -->
list(Ls),
together(Lss).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
Example query:
?- phrase(together([[a],[b,c],[d]]), Ls).
Ls = [a, b, c, d].
In this example, precisely one level of nesting has been removed.

Related

Merging elements of tuples in a list in Prolog

I need to create a list from a knowledgebase that could look like this:
fact1(3,3).
fact1(2,3).
fact1(3,5).
fact1(2,2).
fact1(2,10).
fact1(3,1).
fact1(1,1).
fact1(1,6).
fact2(3,a,b)
fact2(2,c,d)
fact2(1,e,f)
That list needs to contain tuples with each containing the second and third Value of fact2, and the added numbers of fact2, whenever the first value of fact1 and fact2 match up.
Maybe it gets clearer when I show what I have so far.
Here is my predicate with the findall statement, which to me seems to get me the closest to where I need to get:
collect_items(List):-
findall((Out1,Out2,Nr),
(fact2(Val1,Out1,Out2),
fact1(Val1,Nr)),
List).
The List I receive from this, looks like this:
List = [(a,b,3),(a,b,5),(a,b,1),(c,d,3),(c,d,2),(c,d,10),(e,f,1),(e,f,6)]
But really I need the list to look like this:
List = [(a,b,9),(c,d,15),(e,f,7)]
Meaning that, whenever the first two elements of a tuple match up, the numbers, which are the third element of the tuple, should be added together.
I do not know however how to even approach something like this, as I have always read, that as soon as the list is set, it cannot be changed, since prolog is functional and declarative.
So I think I somehow need to match every element against the one before or after it (since the list will always be sortet by the Out1 and Out2 variables), and if they match, add the third value in the tuple together. The problem is, that I have no idea how.
To me it looks like this can not realy be done within the findall itself but would need to be done after the findall
I am a true beginner and would appreciate any help. In this case it would be best, if the solution was all in one predicate.
Here is another solution that uses more than one predicate:
collect_items(Result):-
findall([Out1,Out2,Nr],(fact2(Val1,Out1,Out2),fact1(Val1,Nr)),[[OutA, OutB, N]|B]),
sumElements([[OutA, OutB, N]|B], Result).
sumElements([],[]).
sumElements([[Out, Outt, N]|B], [[Out, Outt, SumLocal]|RestOfList]):-
findall([Out, Outt, X], member([Out, Outt, X], [[Out, Outt, N]|B]), SubList),
sumLocal(SubList, SumLocal),
subtract([[Out, Outt, N]|B], SubList, New),
sumElements(New, RestOfList).
sumLocal([],0).
sumLocal([[_,_,S]|B], T):-
sumLocal(B, R),
T is S + R.
output:
?- collect_items(Result).
Result = [[a, b, 9], [c, d, 15], [e, f, 7]].
with library aggregate:
collect_items(L) :-
setof((U,V,S),
K^aggregate((set(X/Y),sum(N)), (
fact2(K,X,Y),
fact1(K,N)
), ([U/V],S)), L).
we get
?- collect_items(L).
L = [(a, b, 9), (c, d, 15), (e, f, 7)].
You are not right here
since prolog is functional and declarative
Prolog is relational and declarative

Get longest list as goal in prolog

I have more possible list as goal,but i need only one longest list.Is this possible to get first longest list?
li-->[a]|[b]|[c].
int-->['1']|['2']|['3'].
num-->int,num_nl.
num_nl-->num|[].
list1-->num,li.
classify(L,S,R):-list1(S,[]),extract(S,L,R).
extract(S,L1,L2):-append(L11,L22,L1),append(S,L3,L22),append(L11,L3,L2).
Here ERROR: Out of local stack.I want only longest list as goal:
?-classify([c,'1','1',a,f],S,R).
S = ['1', '1', a], R = [c, f] ;
false.
?-classify([c,'1','2','3',a,f,'1','1','2','3',b],S,R).
S = ['1','2','3',a], R = [c, f,'1','1','2','3',b] ;
false.`
You don't provide any detail on how classify/1 is implemented; it could be that you can define it so that it only gives you the longest list.
Your other option is to collect all results, using either findall/3 or bagof/3 or setof/3, then make pairs with the list length as the first element, then sort these pairs and pick the last.
For example:
?- bagof(X, classify(X), Xs),
maplist(length, X, Lengths),
pairs_keys_values(Ps, Lengths, Xs),
keysort(Ps, Sorted),
last(_-Longest, Sorted).
It uses pairs_keys_values/3 and last/2 as defined in the SWI-Prolog standard libraries.
This approach will work, even though it has several problems. It is difficult to discuss those without any knowledge of what classify/1 does.
I used at least once a convoluted variant of Boris' answer
?- R=[_-S|_],setof(L-X,T^(classify(X),length(X,T),L is -1*T),R).

Removing heads from lists in Prolog

I'm trying to write a predicate to remove the head from every list in list of lists and add the tails to a new list. The resulting list should be returned as the second parameter.
Here's the attempt:
construct_new(S,New) :-
New = [],
new_situation(S,New).
new_situation([],_).
new_situation([H|T], New) :-
chop(H, H1),
new_situation(T, [H1|New]).
chop([_|T], T).
You would call it like this:
construct_new([[x,x],[b,c],[d,e,f]],S).
This, however, only produces output true..
Step-by-step execution
Your query is construct_new(Input,Output), for some instanciated Input list.
The first statement in construct_new/2 unifies Output (a.k.a. New) with the empty list. Where is the returned list supposed to be available for the caller? Both arguments are now unified.
You call new_situation(Input,[])
You match the second clause new_situation([H|T],[]), which performs its task recursively (step 4, ...), until ...
You reach new_situation([],_), which successfully discards the intermediate list you built.
Solutions
Write a simple recursive predicate:
new_situation([],[]).
new_situation([[_|L]|T],[L|R]) :-
new_situation(T,R).
Use maplist:
construct_new(S,R) :-
maplist(chop,S,R).
Remark
As pointed out by other answers and comments, your predicates are badly named. construct_new is not a relation, but an action, and could be used to represent almost anything. I tend to like chop because it clearly conveys the act of beheading, but this is not an appropriate name for a relation. repeat's list_head_tail(L,H,T) is declarative and associates variables to their roles. When using maplist, the other predicate (new_situation) doesn't even need to exist...
...even though guillotine/3 is tempting.
This could be done with a DCG:
owth(Lists, Tails) :-
phrase(tails(Tails), Lists).
tails([]) --> [].
tails([T|Tails]) --> [[_|T]], tails(Tails).
Yielding these queries:
| ?- owth([[x,x],[b,c],[d,e,f]], T).
T = [[x],[c],[e,f]] ? ;
no
| ?- owth(L, [[x],[c],[e,f]]).
L = [[_,x],[_,c],[_,e,f]]
yes
(owth = Off with their heads! or, if used the other direction, On with their heads!)
If you also want to capture the heads, you can enhance it as follows:
owth(Lists, Heads, Tails) :-
phrase(tails(Heads, Tails), Lists).
tails([], []) --> [].
tails([H|Hs], [T|Tails]) --> [[H|T]], tails(Hs, Tails).
We use meta-predicate maplist/[3-4] with one of these following auxiliary predicates:
list_tail([_|Xs],Xs).
list_head_tail([X|Xs],X,Xs).
Let's run some queries!
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],Heads,Tails).
Heads = [x,b,d],
Tails = [[x],[c],[e,f]].
If you are only interested in the tails, use maplist/4 together with list_head_tail/3 ...
?- maplist(list_head_tail,[[x,x],[b,c],[d,e,f]],_,Tails).
Tails = [[x],[c],[e,f]].
... or, even simpler, maplist/3 in tandem with list_tail/2:
?- maplist(list_tail,[[x,x],[b,c],[d,e,f]],Tails).
Tails = [[x],[c],[e,f]].
You can also use the somewhat ugly one-liner with findall/3:
?- L = [[x,x],[b,c],[d,e,f]],
findall(T, ( member(M, L), append([_], T, M) ), R).
R = [[x], [c], [e, f]].
(OK, technically a two-liner. Either way, you don't even need to define a helper predicate.)
But definitely prefer the maplist solution that uses chop as shown above.
If you do the maplist expansion by hand, and name your chop/2 a bit better, you would get:
lists_tails([], []).
lists_tails([X|Xs], [T|Ts]) :-
list_tail(X, T),
lists_tails(Xs, Ts).
And since you can do unification in the head of the predicate, you can transform this to:
lists_tails([], []).
lists_tails([[_|T]|Xs], [T|Ts]) :-
lists_tails(Xs, Ts).
But this is identical to what you have in the other answer.
Exercise: why can't we say:
?- maplist(append([_]), R, [[x,x],[b,c],[d,e,f]]).

How can I check if an element in the list is an empty list: []?

How can I check if an element in the list is an empty list: [] ?
I've got the following:
display_degrees([A,B,C,D]):- write(B).
display_degrees([A,B,C,D]):- B==[], nl,write('has no degree'), nl, !.
When I enter in something like:
display_degrees([1,[],3,4]).
I just get: [] instead of 'has no degree'. Is my syntax wrong? Can I not add a clause to this predicate like this?
You're getting this behavior because proof search stops when a goal has succeeded. When you type
display_degrees([1,[],3,4]).
the first rule unifies, and it writes B. Since it was a success, it stops. You can ask Prolog to keep searching, and then it will find the second clause. In swipl, I get
?- [foo].
?- display_degrees([1,[],3,4]).
[]
true r % I type 'r' there
has no degree
true.
If you're just learning Prolog, I suggest you avoid the cut operator ! for some time. Also, doing IO is not the most intuitive thing. I would try some exercises with defining things like natural numbers and recursive functions. E.g., plus:
plus(z, X, X).
plus(s(X), Y, s(Z)) :- plus(X, Y, Z).
The problem with what you have is that the more general rule will fire first. You could switch the order:
display_degrees([A,[],C,D]) :- nl, write('has no degree'), nl, !.
display_degrees([A,B,C,D]) :- write(B).
I could just as well have written for the first predicate:
display_degrees([A,B,C,D]) :- B == [], nl, write('has no degree'), nl, !.
But the "shortcut" I show initially is more idiomatic for a Prolog predicate like this.
I kept the cut since you know you deterministically want one choice. The first rule will match if and only if the second list element is [].
| ?- display_degrees([1,[],3,4]).
has no degree
yes
| ?- display_degrees([1,2,3,4]).
2
yes
| ?-

Prolog transform and separate term (atom) into a list

I have a term (more accurately an atom) like this:
name1(value1),name2(value2)
and I would like to have instead a "real" list like this:
[name1(value1), name2(value2)]
or separeted terms like this:
name1(value1) and name2(value2)
any idea on how to do it?
What about:
ands((A,B)) --> !, ands(A), ands(B).
ands(X) --> [X].
Example:
?- phrase(ands((a,b,c,d)), Ls).
Ls = [a, b, c, d].
In Prolog we use pattern matching to apply different processing to list'elements:
change_list([], []). % end of recursion
change_list([(T1,T2)|Ri], [T1,T2|Ro]) :- % recursive step doing required transformation
!, change_list(Ri, Ro).
change_list([E|Ri], [E|Ro]) :- % catch all rule: copy elem
change_list(Ri, Ro).
simple: for your list [H|T] with T=[] and H the compound term in question that is its head element, have H=','(A,B), List=[A,B].
You can even just write H=(A,B), List=[A,B]. - parentheses are mandatory here.
IOW the data term you're talking about is just an ordinary compound term, with ',' as its functor. If you don't know the structure of these terms in advance, you can inspect it with `=../2':
H =.. [Functor | Arguments].
(I see you got the same advice from #mat).