1 ! :folding=indent:collapseFolds=1:
5 ! Copyright (C) 2003, 2004 Slava Pestov.
7 ! Redistribution and use in source and binary forms, with or without
8 ! modification, are permitted provided that the following conditions are met:
10 ! 1. Redistributions of source code must retain the above copyright notice,
11 ! this list of conditions and the following disclaimer.
13 ! 2. Redistributions in binary form must reproduce the above copyright notice,
14 ! this list of conditions and the following disclaimer in the documentation
15 ! and/or other materials provided with the distribution.
17 ! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 ! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19 ! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 ! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 ! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 ! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 ! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 ! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 ! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 : 2list ( a b -- [ a b ] )
36 #! Construct a proper list of 2 elements.
39 : 3list ( a b c -- [ a b c ] )
40 #! Construct a proper list of 3 elements.
43 : 2rlist ( a b -- [ b a ] )
44 #! Construct a proper list of 2 elements in reverse stack order.
47 : append ( [ list1 ] [ list2 ] -- [ list1 list2 ] )
48 #! Append two lists. The first list must be proper. A new
49 #! list is constructed by copying the first list and setting
50 #! its tail to the second.
51 over [ >r uncons r> append cons ] [ nip ] ifte ;
53 : add ( [ list1 ] elem -- [ list1 elem ] )
54 #! Push a new proper list with an element added to the end.
57 : caar ( list -- caar )
60 : cdar ( list -- cadr )
63 : cadr ( list -- cdar )
66 : cddr ( list -- cddr )
69 : clone-list-iter ( result list -- last [ ] )
70 #! DESTRUCTIVE. Helper word for 'clone-list'.
74 uncons >r unit tuck >r rplacd r> r>
77 : clone-list ( list -- list )
78 #! Push a shallow copy of a list.
80 uncons >r unit dup r> clone-list-iter swap rplacd
83 : contains ( element list -- remainder )
84 #! If the proper list contains the element, push the
85 #! remainder of the list, starting from the cell whose car
86 #! is elem. Otherwise push f.
97 : nth ( n list -- list[n] )
98 #! Gets the nth element of a proper list by successively
99 #! iterating down the cdr pointer.
100 #! Supplying n <= 0 pushes the first element of the list.
101 #! Supplying an argument beyond the end of the list raises
103 swap [ cdr ] times car ;
105 : last* ( list -- last )
106 #! Pushes last cons of a list.
107 #! For example, given a proper list, pushes a cons cell
108 #! whose car is the last element of the list, and whose cdr
110 [ dup cdr cons? ] [ cdr ] while ;
112 : last ( list -- last )
113 #! Pushes last element of a list. Since this pushes the
114 #! car of the last cons cell, the list may be an improper
118 : list? ( list -- boolean )
119 #! Proper list test. A proper list is either f, or a cons
120 #! cell whose cdr is a proper list.
131 : nappend ( [ list1 ] [ list2 ] -- [ list1 list2 ] )
132 #! DESTRUCTIVE. Append two lists. The last node of the first
133 #! list is destructively modified to point to the second
134 #! list, unless the first list is f, in which case the
135 #! second list is returned.
136 over [ over last* rplacd ] [ nip ] ifte ;
138 : first ( list -- obj )
139 #! Push the head of the list, or f if the list is empty.
142 : next ( obj list -- obj )
143 #! Push the next object in the list after an object. Wraps
144 #! around to beginning of list if object is at the end.
146 ! Is there another entry in the list?
157 : nreverse-iter ( list cons -- list cons )
158 [ dup dup cdr 2swap rplacd nreverse-iter ] when* ;
160 : nreverse ( list -- list )
161 #! DESTRUCTIVE. Reverse the given list, without consing.
162 f swap nreverse-iter ;
164 : partition-add ( obj ? ret1 ret2 -- ret1 ret2 )
165 >r >r [ r> cons r> ] [ r> r> swapd cons ] ifte ; inline
167 : partition-step ( ret1 ret2 ref combinator car -- ret1 ret2 )
168 >r 2swap r> -rot >r >r dup >r swap call r> swap r> r>
169 partition-add ; inline
171 : partition-iter ( ret1 ret2 ref combinator list -- ret1 ret2 )
175 r> r> r> partition-iter
178 ] ifte ; inline interpret-only
180 : partition ( ref list combinator -- list1 list2 )
181 #! Compare each element in a proper list against a
182 #! reference element using a combinator. The combinator's
183 #! return value determines if the element is prepended to
184 #! the first or second list.
185 #! The combinator must have stack effect:
186 #! ( ref element -- ? )
187 swap >r >r >r [ ] [ ] r> r> r> partition-iter ;
188 inline interpret-only
190 : sort ( list comparator -- sorted )
191 #! Sort the elements in a proper list using a comparator.
192 #! The comparator must have stack effect:
194 #! To sort elements in descending order, return t if x < y.
195 #! To sort elements in ascending order, return t if x > y.
198 dup >r >r uncons dupd r> partition r>
205 ] ifte ; inline interpret-only
207 : num-sort ( list -- sorted )
208 #! Sorts the list into ascending numerical order.
211 : remove ( obj list -- list )
212 #! Remove all occurrences of the object from the list.
217 uncons swapd remove cons
224 DEFER: tree-contains?
226 : =-or-contains? ( element obj -- ? )
233 : tree-contains? ( element tree -- ? )
235 2dup car =-or-contains? [
241 ! don't bomb on dotted pairs
249 : unique ( elem list -- list )
250 #! Prepend an element to a proper list if it is not
251 #! already contained in the list.
258 : each ( [ list ] [ quotation ] -- )
259 #! Push each element of a proper list in turn, and apply a
260 #! quotation to each element.
262 #! In order to compile, the quotation must consume one more
263 #! value than it produces.
265 >r uncons r> tuck >r >r call r> r> each
268 ] ifte ; inline interpret-only
270 : inject ( list code -- list )
271 #! Applies the code to each item, returns a list that
272 #! contains the result of each application.
274 #! In order to compile, the quotation must consume as many
275 #! values as it produces.
277 ( accum code elem -- accum code )
278 transp over >r >r call r> cons r>
279 ] each drop nreverse ; inline interpret-only
281 : subset-add ( car pred accum -- accum )
282 >r over >r call r> r> rot [ cons ] [ nip ] ifte ;
284 : subset-iter ( accum list pred -- accum )
286 >r unswons r> 2swap pick
287 >r >r subset-add r> r> subset-iter
292 : subset ( list pred -- list )
293 #! Applies a quotation to each element of a list; all
294 #! elements for which the quotation returned a value other
295 #! than f are collected in a new list.
297 #! In order to compile, the quotation must consume as many
298 #! values as it produces.
299 f -rot subset-iter nreverse ; inline interpret-only
301 : length ( list -- length )
302 #! Pushes the length of the given proper list.
303 0 swap [ drop succ ] each ;
305 : leaves ( list -- length )
306 #! Like length, but counts each sub-list recursively.
307 0 swap [ dup list? [ leaves + ] [ drop succ ] ifte ] each ;
309 : reverse ( list -- list )
310 #! Push a new list that is the reverse of a proper list.
311 [ ] swap [ swons ] each ;
313 : all? ( list pred -- ? )
314 #! Push if the predicate returns true for each element of
317 dup >r swap uncons >r swap call [
326 : car= swap car swap car = ;
327 : cdr= swap cdr swap cdr = ;
329 : cons= ( obj cons -- ? )
330 over cons? [ 2dup car= >r cdr= r> and ] [ 2drop f ] ifte ;
332 : cons-hashcode ( cons count -- hash )
336 pred >r uncons r> tuck