Best viewed in 24pt and full-screen
next up previous
Next: From difference-lists to function-lists Up: Representation of lists Previous: Prolog lists

From Prolog lists to difference-lists

In logic programming, the programmation with incomplete structures is a well-known technique. It is even a part where the logic programming paradigm is at its best. One example of this technique is the difference-list (noted List-SubList). A list is represented by the difference between a Prolog list and one of its sublists (the tail of the list) that must be an unknown. For instance, the empty list is represented by X-X and cons(1,cons(2,cons(3,nil))) is represented by [1,2,3|X]-X.

Because the tail is an unknown, two lists can be concatenated with only one unification which is a binding of the tail. Then, a list can be a left concatenand only once in its life.

dconc(A-ZA, ZA-ZB, A-ZB).

dconc3(A-ZA, ZA-ZB, ZB-ZC, A-ZC).

Note that, unlike predicate conc, dconc cannot be used to split a list. Nothing in Prolog enforces the constraint that the tail is a sublist of the list. So Prolog will bind ZA to something which is neither a sublist of A nor a superlist of ZB. Verifying the constraint can only result from a programming discipline. Another difficulty is that testing the empty list requires to perform an occurrence-check because otherwise Prolog is always willing to unify [...|Z]-Z and X-X. Similarly, lack of occurrence-check makes an attempt to concatenate a difference-list to itself succeed and produce an infinite term.

For all these reasons, the following predicates are bogus.

dtwice(L, LL) :- dconc(L, L, LL).  

common_prefix(P, L1, L2) :- dconc(P, _, L1), dconc(P, _, L2).

However, transformation of the representation of lists, followed by some partial evaluation[SS86], generally leads to more efficient programs. nrev can be transformed into the following predicates:

revd1([], Y, Y).
revd1([A|L], Y, Z) :- revd1(L, [A|Y], Z).

revd(L, RL) :- revd1(L, [], RL).

Transforming difference-lists into Prolog lists is trivial (if it is allowed to be destructive as dconc is), but the way back needs to use predicate conc.

dlist2list(L-nil, L).

list2dlist(L, AL-ZL) :- conc(L, ZL, AL).


next up previous
Next: From difference-lists to function-lists Up: Representation of lists Previous: Prolog lists

Olivier Ridoux
Fri Mar 6 11:12:37 MET 1998