/* LISTS.PL */ /* :- module lists. :- public append/3, append_n/2, islist/1, last/2, length/2, member/2, member/3, reverse/2, rev_append/3, nth1/3, nth1/4, delete/3, sublist/3, sublist0/2, sublist1/2. */ /* SPECIFICATION ------------- This module defines some common list predicates, giving them their usual (?) definitions. PUBLIC append( L1?, L2?, L3? ): L3 is the result of appending L2 to L1. PUBLIC append_n( Lists+, Result ): Result is the result of appending all elements of Lists together. PUBLIC rev_append( R+, L+, Result- ): Result is the result of reversing R and prepending it to L. PUBLIC islist( L+ ): L is the null list or something of the form [_|_]. This predicate does not run all the way down L, checking each element. PUBLIC last(Last?, List?): Is true when List is a List and Last is its last element. PUBLIC length( L?, N? ): N is the length of list L. PUBLIC member( Element?, L? ): Element is a member of L. PUBLIC member( Element?, L?, Rest? ): Element is a member of L. Rest is the rest of L. PUBLIC reverse( L1?, L2? ): L2 is the result of reversing L1. PUBLIC nth1( N+, List+, Elem? ): This is true when Elem is the Nth member of List, counting the first as element 1. (That is, throw away the first N-1 elements and unify Elem with the next.) It can only be used to select a particular element given the list and index. PUBLIC nth1( N+, List+, Elem?, Rest? ): This is true when Elem is the Nth member of List, counting the first as element 1, and Rest is the rest of the list. It can only be used to select a particular element given the list and index. PUBLIC delete( List+, Element+, List1- ): Deletes all matches of Element from List, producing List1. Free variables in Element are not bound after the first deletion, so delete( L, (_,X), L1 ) (where X is bound) will delete all pairs (_,X) from L. PUBLIC sublist( Sequence?, SubSequence?, Complement? ): Is true when SubList and Complement are both subsequences of the list List (the order of corresponding elements being preserved) and every element of List which is not in SubList is in the Complement and vice versa. That is, length(List) = length(SubList)+length(Complement), e.g. sublist([1,2,3,4], [1,3,4], [2]). This was written to generate subsets and their complements together, but can also be used to interleave two lists in all possible ways. Note that if S1 is a subset of S2, it will be generated *before S2 as a SubList and *after it as a Complement. N.B. Beware of the order of arguments! I took this version from the Dec-10 library; I'm sure I've seen versions with the sublist argument _first_. PUBLIC sublist0( List+, SubList? ): Is true when SubList is a subsequence of List, but may be List itself. Thus sublist0([a,b], [a,b]) is true as well as sublist0([a,b], [a]). PUBLIC sublist1( List+, SubList? ): Is true when SubList is a proper subsequence of List, that is it contains at least one element less. Thus (assuming you have setof and bagof): ?- setof(X, sublist0([a,b,c],X), Xs). Xs = [[],[a],[a,b],[a,b,c],[a,c],[b],[b,c],[c]] ?- bagof(X, sublist0([a,b,c,d],X), Xs). Xs = [[a,b,c,d],[b,c,d],[c,d],[d],[],[c],[b,d],[b],[b,c],[a,c,d], [a,d],[a],[a,c],[a,b,d],[a,b],[a,b,c]] */ /* IMPLEMENTATION -------------- As usual, reverse and length use accumulator arguments to make tail-recursion optimisation possible. On Poplog, length is already defined, so I've commented out the definition below. Uncomment it if your system lacks it. The obvious definition of 'last' would be last(Last, [Last]) :- !. last(Last, [_|List]) :- last(Last, List). However (see "The Craft of Prolog" section 6.5.4), Prologs with indexing execute that less efficiently than they ought, because the indexing can't distinguish between [_] and [_|_]. I have therefore used O'Keefe's definition. It runs faster on Poplog too, though for different reasons, since Poplog does not index the arguments for last_1. As Steve Knight pointed out to me, in Poplog, you can examine the code for each by setting pop_show_code to true and then loading. nth1 and subseq are taken from the DEC-10 library. */ append([], L, L). append([H|R], S, [H|T]) :- append(R, S, T). append_n( Lists, Result ) :- append_n( Lists, [], Result ). append_n( [], Result, Result ) :- !. append_n( [H|T], SoFar, Result ) :- append_n( T, SoFar, SoFar1 ), append( H, SoFar1, Result ). islist([]) :- !. islist([_|_]). last( Last, [H|T] ) :- last_1( T, H, Last ). last_1( [], Last, Last ) :- !. last_1( [H|T], _, Last ) :- last_1( T, H, Last ). /* length( L, N ) :- length( L, 0, N ). length( [], N, N ) :- !. length( [H|T], N0, N ) :- N1 is N0 + 1, length( T, N1, N ). */ member(X, [X|_]). member(X, [_|Y]) :- member(X, Y). member(X, [X|T], T). member(X, [H|Y], [H|Rest]) :- member(X, Y, Rest). reverse( X, RX ) :- reverse( X, [], RX ). reverse( [], R, R ) :- !. reverse( [X|Y], Z, R ) :- reverse( Y, [X|Z], R ). rev_append( A, B, C ) :- reverse( A, B, C ). nth1(1, [Head|_], Head) :- !. nth1(N, [_|Tail], Elem) :- M is N-1, nth1(M, Tail, Elem). nth1(1, [Head|Tail], Head, Tail) :- !. nth1(N, [Head|Tail], Elem, [Head|Rest]) :- M is N-1, nth1(M, Tail, Elem, Rest). delete( [], _, [] ) :- !. delete( [H1|T], H2, L ) :- not(not(H1=H2)), /* This stops H2's variables getting bound. */ !, delete( T, H2, L ). delete( [X|T], H, [X|L] ) :- delete( T, H, L ). sublist([], [], []). sublist([Head|Tail], Sbsq, [Head|Cmpl]) :- sublist(Tail, Sbsq, Cmpl). sublist([Head|Tail], [Head|Sbsq], Cmpl) :- sublist(Tail, Sbsq, Cmpl). sublist0(List, List). sublist0(List, Rest) :- sublist1(List, Rest). sublist1([_|Tail], Rest) :- sublist0(Tail, Rest). sublist1([Head|Tail], [Head|Rest]) :- sublist1(Tail, Rest). /* :- endmodule. */