1 ! Copyright (C) 2004, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs classes classes.private
4 combinators kernel make math math.order namespaces sequences
12 TUPLE: anonymous-union { members read-only } ;
14 INSTANCE: anonymous-union classoid
16 : <anonymous-union> ( members -- classoid )
17 [ classoid check-instance ] map [ null eq? ] reject
18 members dup length 1 =
19 [ first ] [ sort-classes f like anonymous-union boa ] if ;
21 M: anonymous-union rank-class drop 6 ;
23 TUPLE: anonymous-intersection { participants read-only } ;
25 INSTANCE: anonymous-intersection classoid
27 : <anonymous-intersection> ( participants -- classoid )
28 [ classoid check-instance ] map
29 members dup length 1 =
30 [ first ] [ sort-classes f like anonymous-intersection boa ] if ;
32 M: anonymous-intersection rank-class drop 4 ;
34 TUPLE: anonymous-complement { class read-only } ;
36 INSTANCE: anonymous-complement classoid
38 : <anonymous-complement> ( object -- classoid )
39 classoid check-instance anonymous-complement boa ;
41 M: anonymous-complement rank-class drop 3 ;
43 M: anonymous-complement instance?
44 over [ class>> instance? not ] [ 2drop t ] if ;
46 M: anonymous-complement class-name
53 GENERIC: (classes-intersect?) ( first second -- ? )
59 GENERIC: (flatten-class) ( class -- )
61 GENERIC: normalize-class ( class -- class' )
63 M: object normalize-class ;
65 : symmetric-class-op ( first second cache quot -- result )
66 [ 2dup [ rank-class ] bi@ > [ swap ] when ] 2dip 2cache ; inline
70 : only-classoid? ( obj -- ? )
71 dup classoid? [ class? not ] [ drop f ] if ;
73 : class<= ( first second -- ? )
74 class<=-cache get [ (class<=) ] 2cache ;
76 : class< ( first second -- ? )
78 { [ 2dup class<= not ] [ 2drop f ] }
79 { [ 2dup swap class<= not ] [ 2drop t ] }
80 [ [ rank-class ] bi@ < ]
83 : class= ( first second -- ? )
84 2dup class<= [ swap class<= ] [ 2drop f ] if ;
86 : class-not ( class -- complement )
87 class-not-cache get [ (class-not) ] cache ;
89 : classes-intersect? ( first second -- ? )
90 [ normalize-class ] bi@
91 classes-intersect-cache get [ (classes-intersect?) ] symmetric-class-op ;
93 : class-and ( first second -- class )
94 class-and-cache get [ (class-and) ] symmetric-class-op ;
96 : class-or ( first second -- class )
97 class-or-cache get [ (class-or) ] symmetric-class-op ;
99 SYMBOL: +incomparable+
101 : compare-classes ( first second -- <=> )
102 [ swap class<= ] [ class<= ] 2bi
103 [ +eq+ +lt+ ] [ +gt+ +incomparable+ ] if ? ;
105 : evaluate-class-predicate ( class1 class2 -- ? )
107 { [ 2dup class<= ] [ t ] }
108 { [ 2dup classes-intersect? not ] [ f ] }
114 : superclass<= ( first second -- ? )
115 swap superclass-of [ swap class<= ] [ drop f ] if* ;
117 : left-anonymous-union<= ( first second -- ? )
118 [ members>> ] dip [ class<= ] curry all? ;
120 : right-union<= ( first second -- ? )
121 class-members [ class<= ] with any? ;
123 : right-anonymous-union<= ( first second -- ? )
124 members>> [ class<= ] with any? ;
126 : left-anonymous-intersection<= ( first second -- ? )
127 [ participants>> ] dip [ class<= ] curry any? ;
129 PREDICATE: nontrivial-anonymous-intersection < anonymous-intersection
130 participants>> empty? not ;
132 : right-anonymous-intersection<= ( first second -- ? )
133 participants>> [ class<= ] with all? ;
135 : anonymous-complement<= ( first second -- ? )
136 [ class>> ] bi@ swap class<= ;
138 : normalize-complement ( class -- class' )
139 class>> normalize-class {
140 { [ dup anonymous-union? ] [
142 [ class-not normalize-class ] map
143 <anonymous-intersection>
145 { [ dup anonymous-intersection? ] [
147 [ class-not normalize-class ] map
153 : left-anonymous-complement<= ( first second -- ? )
154 [ normalize-complement ] dip class<= ;
156 PREDICATE: nontrivial-anonymous-complement < anonymous-complement
159 [ anonymous-intersection? ]
161 [ class-participants ]
164 PREDICATE: empty-union < anonymous-union members>> empty? ;
166 PREDICATE: empty-intersection < anonymous-intersection participants>> empty? ;
168 : (class<=) ( first second -- ? )
169 2dup eq? [ 2drop t ] [
170 [ normalize-class ] bi@
171 2dup superclass<= [ 2drop t ] [
173 { [ 2dup eq? ] [ 2drop t ] }
174 { [ dup empty-intersection? ] [ 2drop t ] }
175 { [ over empty-union? ] [ 2drop t ] }
176 { [ 2dup [ anonymous-complement? ] both? ] [ anonymous-complement<= ] }
177 { [ over anonymous-union? ] [ left-anonymous-union<= ] }
178 { [ over nontrivial-anonymous-intersection? ] [ left-anonymous-intersection<= ] }
179 { [ over nontrivial-anonymous-complement? ] [ left-anonymous-complement<= ] }
180 { [ dup class-members ] [ right-union<= ] }
181 { [ dup anonymous-union? ] [ right-anonymous-union<= ] }
182 { [ dup anonymous-intersection? ] [ right-anonymous-intersection<= ] }
183 { [ dup anonymous-complement? ] [ class>> classes-intersect? not ] }
189 M: anonymous-union (classes-intersect?)
190 members>> [ classes-intersect? ] with any? ;
192 M: anonymous-intersection (classes-intersect?)
193 participants>> [ classes-intersect? ] with all? ;
195 M: anonymous-complement (classes-intersect?)
196 class>> class<= not ;
198 : anonymous-union-and ( first second -- class )
199 members>> [ class-and ] with map <anonymous-union> ;
201 : anonymous-intersection-and ( first second -- class )
202 participants>> swap suffix <anonymous-intersection> ;
204 : (class-and) ( first second -- class )
205 2dup compare-classes {
210 2dup classes-intersect? [
211 [ normalize-class ] bi@ {
212 { [ dup anonymous-union? ] [ anonymous-union-and ] }
213 { [ dup anonymous-intersection? ] [ anonymous-intersection-and ] }
214 { [ over anonymous-union? ] [ swap anonymous-union-and ] }
215 { [ over anonymous-intersection? ] [ swap anonymous-intersection-and ] }
216 [ 2array <anonymous-intersection> ]
222 : anonymous-union-or ( first second -- class )
223 members>> swap suffix <anonymous-union> ;
225 : classes>anonymous-union ( first second -- class )
226 [ normalize-class ] bi@ {
227 { [ dup anonymous-union? ] [ anonymous-union-or ] }
228 { [ over anonymous-union? ] [ swap anonymous-union-or ] }
229 [ 2array <anonymous-union> ]
232 : anonymous-complement-or ( first second -- class )
233 2dup class>> swap class<= [ 2drop object ] [ classes>anonymous-union ] if ;
235 : (class-or) ( first second -- class )
236 2dup compare-classes {
242 { [ dup anonymous-complement? ] [ anonymous-complement-or ] }
243 { [ over anonymous-complement? ] [ swap anonymous-complement-or ] }
244 [ classes>anonymous-union ]
249 : (class-not) ( class -- complement )
251 { [ dup anonymous-complement? ] [ class>> ] }
252 { [ dup object eq? ] [ drop null ] }
253 { [ dup null eq? ] [ drop object ] }
254 [ <anonymous-complement> ]
257 M: anonymous-union (flatten-class)
258 members>> [ (flatten-class) ] each ;
262 ERROR: topological-sort-failed ;
264 : largest-class ( seq -- n elt )
265 dup [ [ class< ] with none? ] curry find-last
266 [ topological-sort-failed ] unless* ;
268 : sort-classes ( seq -- newseq )
269 [ class-name ] sort-with >vector
271 [ dup largest-class [ swap remove-nth! ] dip ]
274 : smallest-class ( classes -- class/f )
276 natural-sort <reversed>
277 [ ] [ [ class<= ] most ] map-reduce
280 : flatten-class ( class -- seq )
281 [ (flatten-class) ] { } make members ;