YAP 7.1.0
setof.yap
Go to the documentation of this file.
1/*************************************************************************
2* *
3* YAP Prolog %W% %G%
4* *
5* Yap Prolog was developed at NCCUP - Universidade do Porto *
6* *
7* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8* *
9**************************************************************************
10* *
11* File: setof.pl *
12* Last rev: *
13* mods: *
14* comments: set predicates *
15* *
16*************************************************************************/
17
18/**
19 * @file setof.yap
20 * @author VITOR SANTOS COSTA <vsc@VITORs-MBP.lan>
21 * @date Thu Nov 19 10:45:32 2015
22 *
23 * @brief Setof and friends.
24 *
25 *
26*/
27
28
29:- system_module( '$_setof', [(^)/2,
30 all/3,
31 bagof/3,
34 setof/3], []).
35
36/**
37
38@defgroup Sets Collecting Solutions to a Goal
39@ingroup Builtins
40
41@{
42
43@brief When there are several solutions to a goal, if the user wants to collect all
44the solutions he may be led to use the data base, because backtracking will
45forget previous solutions.
46
47YAP allows the programmer to choose from several system
48predicates instead of writing his own routines. findall/3 gives you
49the fastest, but crudest solution. The other built-in predicates
50post-process the result of the query in several different ways:
51
52
53*/
54
55:- '$catch'/3use_system_module( '$_boot', []).
56
57:- '$do_error'/2use_system_module( '$_errors', []).
58
59% this is used by the all predicate
60
61:- op(50,xfx,same).
62
63
64%% @pred Var ^ Goal
65%
66% The "existential quantifier" symbol is only significant to bagof
67% and setof, which it stops binding the quantified variable.
68%
69
70_^Goal :-
71 '$execute'(Goal).
72
73
74
75/** @pred findall( _T_,+ _G_,- _L_) is iso
76
77findall/3 is a simplified version of bagof which has an implicit
78 existential quantifier on every variable.
79
80Unifies _L_ with a list that contains all the instantiations of the
81term _T_ satisfying the goal _G_.
82
83With the following program:
84
85```
86a(2,1).
87a(1,1).
88a(2,2).
89```
90
91the answer to the query
92
93```
94findall(X,a(X,Y),L).
95```
96
97would be:
98
99```
100X = _32
101Y = _33
102L = [2,1,2];
103no
104```
105
106*/
107findall(Template, Generator, Answers) :-
108 must_be_of_type( list_or_partial_list, Answers ),
109 '$findall'(Template, Generator, [], Answers).
110
111
112/** @pred findall( ?Key, +Goal, +InitialSolutions, -Solutions )
113
114Similar to findall/3, but appends all answers to list _L0_. Useful, if some answers have already been found.
115*/
116findall(Template, Generator, Answers, SoFar) :-
117 must_be_of_type( list_or_partial_list, Answers ),
118 '$findall'(Template, Generator, SoFar, Answers).
119
120% starts by calling the generator,
121% and recording the answers
122'$findall'(Template, Generator, SoFar, Answers) :-
123 '$findall':nb_queue(Ref),
124 (
125 '$execute'(Generator),
126 '$execute':nb_queue_enqueue(Ref, Template),
127 nb_queue_enqueue
128 ;
129 nb_queue_enqueue:nb_queue_close(Ref, Answers, SoFar)
130 ).
131
132
133% findall_with_key is very similar to findall, but uses the SICStus
134% algorithm to guarantee that variables will have the same names.
135%
136'$findall_with_common_vars'(Template, Generator, Answers) :-
137 '$findall_with_common_vars':nb_queue(Ref),
138 (
139 '$execute'(Generator),
140 '$execute':nb_queue_enqueue(Ref, Template),
141 nb_queue_enqueue
142 ;
143 nb_queue_enqueue:nb_queue_close(Ref, Answers, []),
144 '$collect_with_common_vars'(Answers, _)
145 ).
146
147
148'$collect_with_common_vars'([], _).
149'$collect_with_common_vars'([Key-_|Answers], VarList) :-
150 '$variables_in_term'(Key, _, VarList),
151 '$collect_with_common_vars'(Answers, VarList).
152
153/** @pred setof( _X_,+ _P_,- _B_) is iso
154
155Similar to `bagof( _T_, _G_, _L_)` but sorts list
156 _L_ and keeping only one copy of each element. Again, assuming the
157same clauses as in the examples above, the reply to the query
158
159```
160setof(X,a(X,Y),L).
161```
162would be:
163
164```
165X = _32
166Y = 1
167L = [1,2];
168X = _32
169Y = 2
170L = [2];
171no
172```
173 */
174setof(Template, Generator, Set) :-
175
176 ( '$is_list_or_partial_list'(Set) ->
177 '$is_list_or_partial_list'
178 ;
179 '$do_error'(type_error(list,Set), setof(Template, Generator, Set))
180 ),
181 '$bagof'(Template, Generator, Bag),
182 '$sort'(Bag, Set).
183
184
185
186
187
188/**
189 @pred bagof( _T_,+ _G_,- _L_) is iso
190
191
192For each set of possible instances of the free variables occurring in
193_G_ but not in _T_, generates the list _L_ of the instances of
194 _T_ satisfying _G_. Again, assuming the same clauses as in the
195examples above, the reply to the query
196
197```
198?- bagof(X,a(X,Y),L).
199
200X = _32
201Y = 1
202L = [2,1];
203X = _32
204Y = 2
205L = [2];
206no
207```
208% And this is bagof/3
209
210% Either we have excess of variables
211% and we need to find the solutions for each instantiation
212% of these variables
213*/
214bagof(Template, Generator, Bag) :-
215 ( '$is_list_or_partial_list'(Bag) ->
216 '$is_list_or_partial_list'
217 ;
218 '$do_error'(type_error(list,Bag), bagof(Template, Generator, Bag))
219 ),
220 '$bagof'(Template, Generator, Bag).
221
222'$bagof'(Template, Generator, Bag) :-
223 '$free_variables_in_term'(Template^Generator, StrippedGenerator, Key),
224 %format('TemplateV=~w v=~w ~w~n',[TemplateV,Key, StrippedGenerator]),
225 ( Key \== '$' ->
226 '$findall_with_common_vars'(Key-Template, StrippedGenerator, Bags0),
227 '$keysort'(Bags0, Bags),
228 '$pick'(Bags, Key, Bag)
229 ;
230 '$findall'(Template, StrippedGenerator, [], Bag0),
231 Bag0 \== [],
232 Bag = Bag0
233 ).
234
235
236% picks a solution attending to the free variables
237'$pick'([K-X|Bags], Key, Bag) :-
238 '$parade'(Bags, K, Bag1, Bags1),
239 '$decide'(Bags1, [X|Bag1], K, Key, Bag).
240
241'$parade'([K-X|L1], Key, [X|B], L) :- '$parade':variant(K, Key), variant,
242 K= Key,
243 '$parade'(L1, Key, B, L).
244'$parade'(L, _, [], L).
245
246%
247% The first argument to decide gives if solutions still left;
248% The second gives the solution currently found;
249% The third gives the free variables that are supposed to be bound;
250% The fourth gives the free variables being currently used.
251% The fifth outputs the current solution.
252%
253'$decide'([], Bag, Key0, Key, Bag) :- '$decide',
254 Key0=Key.
255'$decide'(_, Bag, Key, Key, Bag).
256'$decide'(Bags, _, _, Key, Bag) :-
257 '$pick'(Bags, Key, Bag).
258
259% as an alternative to setof you can use the predicate all(Term,Goal,Solutions)
260% But this version of all does not allow for repeated answers
261% if you want them use findall
262
263/**
264 @pred all( _T_,+ _G_,- _L_)
265
266
267Similar to `findall( _T_, _G_, _L_)` but eliminate
268repeated elements. Thus, assuming the same clauses as in the above
269example, the reply to the query
270
271```
272all(X,a(X,Y),L).
273```
274would be:
275
276```
277X = _32
278Y = _33
279L = [2,1];
280no
281```
282
283Note that all/3 will fail if no answers are found.
284
285
286*/
287all(T, G same X,S) :- all, all(T same X,G,Sx), '$$produce'(Sx,S,X).
288all(T,G,S) :-
289 '$init_db_queue'(Ref),
290 ( catch(G, Error,'$clean_findall'(Ref,Error) ),
291 '$execute'(G),
292 '$db_enqueue'(Ref, T),
293 '$db_enqueue'
294 ;
295 '$$set'(S,Ref)
296 ).
297
298% $$set does its best to preserve space
299'$$set'(S,R) :-
300 '$$build'(S0,_,R),
301 S0 = [_|_],
302 S = S0.
303
304'$$build'(Ns,S0,R) :- '$db_dequeue'(R,X), '$db_dequeue',
305 '$$build2'(Ns,S0,R,X).
306'$$build'([],_,_).
307
308'$$build2'([X|Ns],Hash,R,X) :-
309 '$$new'(Hash,X), '$$new',
310 '$$build'(Ns,Hash,R).
311'$$build2'(Ns,Hash,R,_) :-
312 '$$build'(Ns,Hash,R).
313
314'$$new'(V,El) :- var(V), var, V = n(_,El,_).
315'$$new'(n(R,El0,L),El) :-
316 compare(C,El0,El),
317 '$$new'(C,R,L,El).
318
319'$$new'(=,_,_,_) :- '$$new', '$$new'.
320'$$new'(<,R,_,El) :- '$$new'(R,El).
321'$$new'(>,_,L,El) :- '$$new'(L,El).
322
323
324'$$produce'([T1 same X1|Tn],S,X) :- '$$split'(Tn,T1,X1,S1,S2),
325 ( S=[T1|S1], X=X1;
326 !, produce(S2,S,X) ).
327
328'$$split'([],_,_,[],[]).
329'$$split'([T same X|Tn],T,X,S1,S2) :- '$$split'(Tn,T,X,S1,S2).
330'$$split'([T1 same X|Tn],T,X,[T1|S1],S2) :- '$$split'(Tn,T,X,S1,S2).
331'$$split'([T1|Tn],T,X,S1,[T1|S2]) :- '$$split'(Tn,T,X,S1,S2).
332
333/**
334@}
335*/
336
catch( : Goal,+ Exception,+ Action)
op(+ P,+ T,+ A)
all( T,+ G,- L)
bagof( T,+ G,- L)
findall( T,+ G,- L)
Definition: setof.yap:70
findall( ?Key, +Goal, +InitialSolutions, -Solutions )
setof( X,+ P,- B)
variant(? Term1, ? Term2)
var( T)
nb_queue(- Queue)
nb_queue_close(+ Queue, - Head, ? Tail)
nb_queue_enqueue(+ Queue, + Element)