| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | ! Copyright (C) 2004, 2008 Slava Pestov. | 
					
						
							|  |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2008-04-03 22:19:20 -04:00
										 |  |  | USING: kernel classes classes.builtin combinators accessors | 
					
						
							|  |  |  | sequences arrays vectors assocs namespaces words sorting layouts | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  | math hashtables kernel.private sets math.order ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | IN: classes.algebra | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : 2cache ( key1 key2 assoc quot -- value )
 | 
					
						
							|  |  |  |     >r >r 2array r> [ first2 ] r> compose cache ; inline
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  | DEFER: (class<=) | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  | : class<= ( first second -- ? )
 | 
					
						
							|  |  |  |     class<=-cache get [ (class<=) ] 2cache ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | DEFER: (class-not) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : class-not ( class -- complement )
 | 
					
						
							|  |  |  |     class-not-cache get [ (class-not) ] cache ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEFER: (classes-intersect?) ( first second -- ? )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : classes-intersect? ( first second -- ? )
 | 
					
						
							|  |  |  |     classes-intersect-cache get [ (classes-intersect?) ] 2cache ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEFER: (class-and) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : class-and ( first second -- class )
 | 
					
						
							|  |  |  |     class-and-cache get [ (class-and) ] 2cache ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DEFER: (class-or) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : class-or ( first second -- class )
 | 
					
						
							|  |  |  |     class-or-cache get [ (class-or) ] 2cache ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TUPLE: anonymous-union members ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | C: <anonymous-union> anonymous-union | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | TUPLE: anonymous-intersection participants ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | C: <anonymous-intersection> anonymous-intersection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TUPLE: anonymous-complement class ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | C: <anonymous-complement> anonymous-complement | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  | : superclass<= ( first second -- ? )
 | 
					
						
							|  |  |  |     >r superclass r> class<= ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | : left-anonymous-union<= ( first second -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |     >r members>> r> [ class<= ] curry all? ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | : right-anonymous-union<= ( first second -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |     members>> [ class<= ] with contains? ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | : left-anonymous-intersection<= ( first second -- ? )
 | 
					
						
							|  |  |  |     >r participants>> r> [ class<= ] curry contains? ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | : right-anonymous-intersection<= ( first second -- ? )
 | 
					
						
							|  |  |  |     participants>> [ class<= ] with all? ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | : anonymous-complement<= ( first second -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |     [ class>> ] bi@ swap class<= ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  | : normalize-class ( class -- class' )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ dup members ] [ members <anonymous-union> ] } | 
					
						
							|  |  |  |         { [ dup participants ] [ participants <anonymous-intersection> ] } | 
					
						
							|  |  |  |         [ ] | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : normalize-complement ( class -- class' )
 | 
					
						
							|  |  |  |     class>> normalize-class { | 
					
						
							|  |  |  |         { [ dup anonymous-union? ] [ | 
					
						
							|  |  |  |             members>> | 
					
						
							|  |  |  |             [ class-not normalize-class ] map
 | 
					
						
							|  |  |  |             <anonymous-intersection>  | 
					
						
							|  |  |  |         ] } | 
					
						
							|  |  |  |         { [ dup anonymous-intersection? ] [ | 
					
						
							|  |  |  |             participants>> | 
					
						
							|  |  |  |             [ class-not normalize-class ] map
 | 
					
						
							|  |  |  |             <anonymous-union> | 
					
						
							|  |  |  |         ] } | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : left-anonymous-complement<= ( first second -- ? )
 | 
					
						
							|  |  |  |     >r normalize-complement r> class<= ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PREDICATE: nontrivial-anonymous-complement < anonymous-complement | 
					
						
							|  |  |  |     class>> { | 
					
						
							|  |  |  |         [ anonymous-union? ] | 
					
						
							|  |  |  |         [ anonymous-intersection? ] | 
					
						
							|  |  |  |         [ members ] | 
					
						
							|  |  |  |         [ participants ] | 
					
						
							|  |  |  |     } cleave or or or ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 02:37:37 -04:00
										 |  |  | PREDICATE: empty-union < anonymous-union members>> empty? ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PREDICATE: empty-intersection < anonymous-intersection participants>> empty? ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  | : (class<=) ( first second -- -1/0/1 )
 | 
					
						
							| 
									
										
										
										
											2008-05-11 02:37:37 -04:00
										 |  |  |     2dup eq? [ 2drop t ] [ | 
					
						
							|  |  |  |         [ normalize-class ] bi@ { | 
					
						
							|  |  |  |             { [ dup empty-intersection? ] [ 2drop t ] } | 
					
						
							|  |  |  |             { [ over empty-union? ] [ 2drop t ] } | 
					
						
							|  |  |  |             { [ 2dup [ anonymous-complement? ] both? ] [ anonymous-complement<= ] } | 
					
						
							|  |  |  |             { [ over anonymous-union? ] [ left-anonymous-union<= ] } | 
					
						
							|  |  |  |             { [ over anonymous-intersection? ] [ left-anonymous-intersection<= ] } | 
					
						
							|  |  |  |             { [ over nontrivial-anonymous-complement? ] [ left-anonymous-complement<= ] } | 
					
						
							|  |  |  |             { [ dup anonymous-union? ] [ right-anonymous-union<= ] } | 
					
						
							|  |  |  |             { [ dup anonymous-intersection? ] [ right-anonymous-intersection<= ] } | 
					
						
							|  |  |  |             { [ dup anonymous-complement? ] [ class>> classes-intersect? not ] } | 
					
						
							|  |  |  |             { [ over superclass ] [ superclass<= ] } | 
					
						
							|  |  |  |             [ 2drop f ] | 
					
						
							|  |  |  |         } cond
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : anonymous-union-intersect? ( first second -- ? )
 | 
					
						
							|  |  |  |     members>> [ classes-intersect? ] with contains? ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : anonymous-intersection-intersect? ( first second -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  |     participants>> [ classes-intersect? ] with all? ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : anonymous-complement-intersect? ( first second -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |     class>> class<= not ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : tuple-class-intersect? ( first second -- ? )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ over tuple eq? ] [ 2drop t ] } | 
					
						
							|  |  |  |         { [ over builtin-class? ] [ 2drop f ] } | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |         { [ over tuple-class? ] [ [ class<= ] [ swap class<= ] 2bi or ] } | 
					
						
							| 
									
										
										
										
											2008-04-11 13:53:22 -04:00
										 |  |  |         [ swap classes-intersect? ] | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : builtin-class-intersect? ( first second -- ? )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ 2dup eq? ] [ 2drop t ] } | 
					
						
							|  |  |  |         { [ over builtin-class? ] [ 2drop f ] } | 
					
						
							| 
									
										
										
										
											2008-04-11 13:53:22 -04:00
										 |  |  |         [ swap classes-intersect? ] | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : (classes-intersect?) ( first second -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  |     normalize-class { | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |         { [ dup anonymous-union? ] [ anonymous-union-intersect? ] } | 
					
						
							|  |  |  |         { [ dup anonymous-intersection? ] [ anonymous-intersection-intersect? ] } | 
					
						
							|  |  |  |         { [ dup anonymous-complement? ] [ anonymous-complement-intersect? ] } | 
					
						
							|  |  |  |         { [ dup tuple-class? ] [ tuple-class-intersect? ] } | 
					
						
							|  |  |  |         { [ dup builtin-class? ] [ builtin-class-intersect? ] } | 
					
						
							|  |  |  |         { [ dup superclass ] [ superclass classes-intersect? ] } | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  | : anonymous-union-and ( first second -- class )
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     members>> [ class-and ] with map <anonymous-union> ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  | : anonymous-intersection-and ( first second -- class )
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  |     participants>> swap suffix <anonymous-intersection> ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : (class-and) ( first second -- class )
 | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |         { [ 2dup class<= ] [ drop ] } | 
					
						
							|  |  |  |         { [ 2dup swap class<= ] [ nip ] } | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |         { [ 2dup classes-intersect? not ] [ 2drop null ] } | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  |         [ | 
					
						
							|  |  |  |             [ normalize-class ] bi@ { | 
					
						
							|  |  |  |                 { [ dup anonymous-union? ] [ anonymous-union-and ] } | 
					
						
							|  |  |  |                 { [ dup anonymous-intersection? ] [ anonymous-intersection-and ] } | 
					
						
							|  |  |  |                 { [ over anonymous-union? ] [ swap anonymous-union-and ] } | 
					
						
							|  |  |  |                 { [ over anonymous-intersection? ] [ swap anonymous-intersection-and ] } | 
					
						
							|  |  |  |                 [ 2array <anonymous-intersection> ] | 
					
						
							|  |  |  |             } cond
 | 
					
						
							|  |  |  |         ] | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  | : anonymous-union-or ( first second -- class )
 | 
					
						
							| 
									
										
										
										
											2008-03-31 20:18:05 -04:00
										 |  |  |     members>> swap suffix <anonymous-union> ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  | : ((class-or)) ( first second -- class )
 | 
					
						
							|  |  |  |     [ normalize-class ] bi@ { | 
					
						
							|  |  |  |         { [ dup anonymous-union? ] [ anonymous-union-or ] } | 
					
						
							|  |  |  |         { [ over anonymous-union? ] [ swap anonymous-union-or ] } | 
					
						
							|  |  |  |         [ 2array <anonymous-union> ] | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : anonymous-complement-or ( first second -- class )
 | 
					
						
							|  |  |  |     2dup class>> swap class<= [ 2drop object ] [ ((class-or)) ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | : (class-or) ( first second -- class )
 | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |         { [ 2dup class<= ] [ nip ] } | 
					
						
							|  |  |  |         { [ 2dup swap class<= ] [ drop ] } | 
					
						
							| 
									
										
										
										
											2008-05-11 00:59:02 -04:00
										 |  |  |         { [ dup anonymous-complement? ] [ anonymous-complement-or ] } | 
					
						
							|  |  |  |         { [ over anonymous-complement? ] [ swap anonymous-complement-or ] } | 
					
						
							|  |  |  |         [ ((class-or)) ] | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : (class-not) ( class -- complement )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ dup anonymous-complement? ] [ class>> ] } | 
					
						
							|  |  |  |         { [ dup object eq? ] [ drop null ] } | 
					
						
							|  |  |  |         { [ dup null eq? ] [ drop object ] } | 
					
						
							| 
									
										
										
										
											2008-04-11 13:53:22 -04:00
										 |  |  |         [ <anonymous-complement> ] | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  | : class< ( first second -- ? )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ 2dup class<= not ] [ 2drop f ] } | 
					
						
							|  |  |  |         { [ 2dup swap class<= not ] [ 2drop t ] } | 
					
						
							|  |  |  |         [ [ rank-class ] bi@ < ] | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-02 18:36:31 -04:00
										 |  |  | : largest-class ( seq -- n elt )
 | 
					
						
							|  |  |  |     dup [ [ class< ] with contains? not ] curry find-last
 | 
					
						
							|  |  |  |     [ "Topological sort failed" throw ] unless* ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : sort-classes ( seq -- newseq )
 | 
					
						
							| 
									
										
										
										
											2008-05-02 18:36:31 -04:00
										 |  |  |     [ [ word-name ] compare ] sort >vector
 | 
					
						
							|  |  |  |     [ dup empty? not ] | 
					
						
							|  |  |  |     [ dup largest-class >r over delete-nth r> ] | 
					
						
							|  |  |  |     [ ] unfold nip ;
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | : min-class ( class seq -- class/f )
 | 
					
						
							| 
									
										
										
										
											2008-04-26 00:12:44 -04:00
										 |  |  |     over [ classes-intersect? ] curry filter
 | 
					
						
							| 
									
										
										
										
											2008-04-19 03:11:40 -04:00
										 |  |  |     dup empty? [ 2drop f ] [ | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |         tuck [ class<= ] with all? [ peek ] [ drop f ] if
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  | DEFER: (flatten-class) | 
					
						
							|  |  |  | DEFER: flatten-builtin-class | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : flatten-intersection-class ( class -- )
 | 
					
						
							|  |  |  |     participants [ flatten-builtin-class ] map
 | 
					
						
							|  |  |  |     dup empty? [ | 
					
						
							| 
									
										
										
										
											2008-05-11 02:37:37 -04:00
										 |  |  |         drop builtins get [ (flatten-class) ] each
 | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  |     ] [ | 
					
						
							|  |  |  |         unclip [ assoc-intersect ] reduce [ swap set ] assoc-each
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  | : (flatten-class) ( class -- )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ dup tuple-class? ] [ dup set ] } | 
					
						
							|  |  |  |         { [ dup builtin-class? ] [ dup set ] } | 
					
						
							|  |  |  |         { [ dup members ] [ members [ (flatten-class) ] each ] } | 
					
						
							| 
									
										
										
										
											2008-05-10 19:09:05 -04:00
										 |  |  |         { [ dup participants ] [ flatten-intersection-class ] } | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |         { [ dup superclass ] [ superclass (flatten-class) ] } | 
					
						
							| 
									
										
										
										
											2008-04-11 13:53:22 -04:00
										 |  |  |         [ drop ] | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : flatten-class ( class -- assoc )
 | 
					
						
							|  |  |  |     [ (flatten-class) ] H{ } make-assoc ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : flatten-builtin-class ( class -- assoc )
 | 
					
						
							|  |  |  |     flatten-class [ | 
					
						
							| 
									
										
										
										
											2008-05-02 03:51:38 -04:00
										 |  |  |         dup tuple class<= [ 2drop tuple tuple ] when
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     ] assoc-map ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : class-types ( class -- seq )
 | 
					
						
							|  |  |  |     flatten-builtin-class keys
 | 
					
						
							|  |  |  |     [ "type" word-prop ] map natural-sort ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : class-tags ( class -- tag/f )
 | 
					
						
							|  |  |  |     class-types [ | 
					
						
							|  |  |  |         dup num-tags get >=
 | 
					
						
							| 
									
										
										
										
											2008-04-02 19:50:21 -04:00
										 |  |  |         [ drop \ hi-tag tag-number ] when
 | 
					
						
							| 
									
										
										
										
											2008-03-24 20:52:21 -04:00
										 |  |  |     ] map prune ;
 |