Predicate to convert list to conjunction

Is there a predicate to convert a list to a conjuction? i.e. something like:

?- list_conjuction([a,b,c,d],Conj), write_canonical(Conj).
','(a,','(b,','(c,d)))
Conj =  (a, b, c, d).

Not as far as I know, but it’s pretty easy to write:

list_conjunction([], true).
list_conjunction([X], X) :- !.
list_conjunction([X|Xs], (X, Conj)) :-
    list_conjunction(Xs, Conj).

EDIT: Paulo’s solution below is better, as it works properly when using with an unbound list & bound conjunction.

You can easily write one. For example:

list_to_conjunction([], true).
list_to_conjunction([Goal| Goals], Conjunction) :-
	list_to_conjunction(Goals, Goal, Conjunction).

list_to_conjunction([], Conjunction, Conjunction).
list_to_conjunction([Goal| Goals], Conjunction0, Conjunction) :-
	list_to_conjunction(Goals, (Conjunction0, Goal), Conjunction).
1 Like

Thanks @james, what I did was

list_conjuction([H],H).
list_conjuction([H,H1|T],(H,Conj)) :-
   list_conjuction([H1|T],Conj).

missed the

list_conjunction([],true).

EDIT: Paulo or James, you see any problem with it?

I think the reason Paulo’s solution is structured the way it is is that the solution you write leaves a choice-point behind for the [H], H case. That’s why I added the cut in my solution, but that makes it behave probably not as desired if you leave the list unbound & have the conjunction be instantiated. The trade-off is that Paulo’s has the precedence switched, I think (i.e. it yields (((a, b), c), d) instead of (a, (b, (c, d))).

1 Like

Here’s another solution which is probably uglier, but doesn’t leave choice-points, uses the desired associativity, and works in both modes

list_conjunction([], true).
list_conjunction([X], X) :- \+ (X = (_,_)), !.
list_conjunction([X|Xs], (X, Conj)) :-
    list_conjunction(Xs, Conj).

I thought SWI-Prolog was able to see that [H],H and [H,H1|T],(H,Conj) are mutually exclusive by their structure, since I remember reading some time ago that there was special handling of lists and choice points in some of the SWI-Prolog docs. Am I wrong in this?

In this case, because [X] can unify with [X|Xs] when Xs = []. Probably could re-write that to be [X,Y|Xs], but that also seems to leave a choice point behind. I don’t know enough about how SWI’s argument indexing works to say why…I know it won’t leave behind choice points for [] vs [X|Xs], but I don’t know if it looks into more detail than that.

This is exactly what I did:

% ....
list_conjuction([H,H1|T],(H,Conj)) :-
   list_conjuction([H1|T],Conj).

but in practice it still leaves a choice point. The compiler is not smart enough yet to figure out that [H] and [H,H1|T] can never unify. Thanks to both of you.

1 Like

As @jamesnvc explained, my version takes advantage of first-argument indexing to avoid leaving choice points without using cuts (assuming the first argument bound to a list). The following variant keeps the precedence that you may expect from a list of goals:

list_to_conjunction([], true).
list_to_conjunction([Goal| Goals], Conjunction) :-
	list_to_conjunction(Goals, Goal, Conjunction).

list_to_conjunction([], Conjunction, Conjunction).
list_to_conjunction([Next| Goals], Goal, (Goal,Conjunction)) :-
	list_to_conjunction(Goals, Next, Conjunction).

Sample calls:

?- list_to_conjunction([a,b,c], Conjunction),  write_canonical(Conjunction).
','(a,','(b,c))
Conjunction =  (a, b, c).

?- write_canonical((a,b,c)).
','(a,','(b,c))
true.

?- list_to_conjunction([a,b,c,d,e], Conjunction),  write_canonical(Conjunction).
','(a,','(b,','(c,','(d,e))))
Conjunction =  (a, b, c, d, e).

?- write_canonical((a,b,c,d,e)).
','(a,','(b,','(c,','(d,e))))
true.

?- list_to_conjunction([a], Conjunction),  write_canonical(Conjunction).
a
Conjunction = a.

?- list_to_conjunction([a,b], Conjunction),  write_canonical(Conjunction).
','(a,b)
Conjunction =  (a, b).
2 Likes

And in 8.1.x in the library comma_list/2

1 Like

Thanks for this! This is the reason I wrote the post: I suspected that this predicate already existed within SWI-Prolog.

One of the things I have come to notice is that there are many, many very useful predicates hidden in SWI-Prolog, they are all indexed in Jan’s brain though, and I have no idea how that index could be serialized for human transmission :slight_smile:

That happens slowly by making questions and answers indexed by Google :slight_smile: Apart from that, I guess the only way is to improve the documentation and search over the documentation. There have been several discussions that produced good ideas, but in the end it requires some people to actually work on them.

Usually, a Google search such as swipl table produces pretty good results. But in this case, swipl comma list failed me (swipl comma_list sort of worked; but that also required knowing the name of the predicate, which was the whole point of the exercise). However, typing in “comma” into the documentation search window for SWI-Prolog did work.

I’ve also had problems with searching for dict documentation – Google search tends to not get the main results (its first result is the dict utilities) but the SWI-Prolog documentation drop-down is better.

1 Like

Yes, I think this is working very well. If you type ‘comma’ or ‘conjunction’ in the drop-down and press enter the results include the comma_list predicate.