# Predicate to convert list to conjunction

**URL:** <https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100>\
**Category:** Predicate\
**Created:** [April 3, 2020, 7:52pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100 "2020-04-03T19:52:37Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [April 3, 2020, 7:52pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/1 "2020-04-03T19:52:37Z")

</div>

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

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

```

---

<div class="post-metadata">

**Author:** ![jamesnvc](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jamesnvc/32/14_2.png) [@jamesnvc](https://swi-prolog.discourse.group/u/jamesnvc)\
**Post date:** [April 3, 2020, 7:58pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/2 "2020-04-03T19:58:10Z")

</div>

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

```prolog
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.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [April 3, 2020, 7:58pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/3 "2020-04-03T19:58:51Z")

</div>

You can easily write one. For example:

```prolog
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).

```

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [April 3, 2020, 8:00pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/4 "2020-04-03T20:00:34Z")

</div>

Thanks @james, what I did was

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

```

missed the

```prolog
list_conjunction([],true).

```

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

---

<div class="post-metadata">

**Author:** ![jamesnvc](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jamesnvc/32/14_2.png) [@jamesnvc](https://swi-prolog.discourse.group/u/jamesnvc)\
**Post date:** [April 3, 2020, 8:05pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/5 "2020-04-03T20:05:34Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![jamesnvc](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jamesnvc/32/14_2.png) [@jamesnvc](https://swi-prolog.discourse.group/u/jamesnvc)\
**Post date:** [April 3, 2020, 8:09pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/6 "2020-04-03T20:09:01Z")

</div>

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

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

```

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [April 3, 2020, 8:14pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/7 "2020-04-03T20:14:00Z")

</div>

> [@jamesnvc](#):
>
> 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.

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?

---

<div class="post-metadata">

**Author:** ![jamesnvc](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jamesnvc/32/14_2.png) [@jamesnvc](https://swi-prolog.discourse.group/u/jamesnvc)\
**Post date:** [April 3, 2020, 8:18pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/8 "2020-04-03T20:18:43Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [April 3, 2020, 8:22pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/9 "2020-04-03T20:22:07Z")

</div>

> [@jamesnvc](#):
>
> Probably could re-write that to be `[X,Y|Xs]`

This is exactly what I did:

```prolog
% ....
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.

---

<div class="post-metadata">

**Author:** ![pmoura](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pmoura/32/11_2.png) [@pmoura](https://swi-prolog.discourse.group/u/pmoura)\
**Post date:** [April 3, 2020, 9:10pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/10 "2020-04-03T21:10:18Z")

</div>

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:

```prolog
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:

```nohighlight
?- 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).

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 4, 2020, 7:26am UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/11 "2020-04-04T07:26:12Z")

</div>

And in 8.1.x in the library [comma\_list/2](https://www.swi-prolog.org/pldoc/doc_for?object=prolog_code%3Acomma_list/2)

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [April 4, 2020, 3:51pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/12 "2020-04-04T15:51:20Z")

</div>

> [@jan](#):
>
> And in 8.1.x in the library [comma\_list/2](https://www.swi-prolog.org/pldoc/doc_for?object=prolog_code%3Acomma_list/2)

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 🙂

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [April 4, 2020, 4:42pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/13 "2020-04-04T16:42:15Z")

</div>

> [@swi](#):
>
> I have no idea how that index could be serialized for human transmission

That happens slowly by making questions and answers indexed by Google 🙂 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.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [April 4, 2020, 5:03pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/14 "2020-04-04T17:03:45Z")

</div>

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](https://www.swi-prolog.org/pldoc/man?section=dicts)) but the SWI-Prolog documentation drop-down is better.

---

<div class="post-metadata">

**Author:** ![swi](https://avatars.discourse-cdn.com/v4/letter/s/51bf81/32.png) [@swi](https://swi-prolog.discourse.group/u/swi)\
**Post date:** [April 4, 2020, 5:07pm UTC](https://swi-prolog.discourse.group/t/predicate-to-convert-list-to-conjunction/2100/15 "2020-04-04T17:07:26Z")

</div>

> [@peter.ludemann](#):
>
> SWI-Prolog documentation drop-down is better

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.
