2

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!

avish12
  • 107
  • 8

1 Answers1

3

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 (). 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.

mat
  • 40,498
  • 3
  • 51
  • 78
  • Hi Mat, I understand the mismatch in the example and understand your explanation about DCG. What I don't understand is why can't I just use append/2 if it is native in the language - it seems that it does exactly what I need... Moreover, I tried to translate the DCG code into rules and facts code but it didn't yield the same result. Can you help finding what should I fix here? new_together([], []). new_together([Ls|Lss], [NewLs|NewLss]) :- new_list(Ls, NewLs), new_together(Lss, NewLss). new_list([], []). new_list([L|Ls], [L|NewLs]) :- new_list(Ls,NewLs). Thanks! – avish12 Jul 10 '16 at 16:45
  • 1
    You can **and should** of course use the predefined `append/2` in real-life programs if your Prolog system already provides this predicate. However, you should also learn how to write such predicates yourself if you do not yet know how to do that, to get a better understanding of these relations, and also so that you can easily implement slight variations if you need them. To see how the DCG I gave can be translated to Prolog clauses, use `listing/1`, such as `?- listing(together//1).` – mat Jul 10 '16 at 16:50