YAP 7.1.0
meta.yap
Go to the documentation of this file.
1/**
2
3 @file meta.yap
4
5 @defgroup YAPMetaPredicates Using Meta-Calls with Modules
6 @ingroup YAPModules
7 @{
8
9 @pred meta_predicate(G1 , Gj , Gn) is directive
10
11Declares that this predicate manipulates references to predicates.
12Each _Gi_ is a mode specification.
13
14If the argument is `:`, it does not refer directly to a predicate
15but must be module expanded. If the argument is an integer, the argument
16is a goal or a closure and must be expanded. Otherwise, the argument is
17not expanded. Note that the system already includes declarations for all
18built-ins.
19
20For example, the declaration for call/1 and setof/3 are:
21
22```
23:- meta_predicate call(0), setof(?,0,?).
24```
25
26meta_predicate declaration
27 implemented by asserting
28
29meta_predicate(SourceModule,Declaration)
30
31*/
32
33% directive now meta_predicate Ps :- $meta_predicate(Ps).
34
35:- '$c_built_in'/4use_system_module( '$_arith', []).
36
37%% handle module transparent predicates by defining a
38%% new context module.
39'$is_mt'(H, B, HM, _SM, M, (context_module(CM),B), CM) :-
40 '$yap_strip_module'(HM:H, M, NH),
41 '$module_transparent'(_, M, _, NH).
42
43
44% I assume the clause has been processed, so the
45% var case is long gone! Yes :)
46
47'$clean_cuts'(!,true):- '$clean_cuts'.
48'$clean_cuts'(G,(current_choice_point(DCP),NG)) :-
49 '$conj_has_cuts'(G,DCP,NG,OK), OK == '$conj_has_cuts', '$conj_has_cuts'.
50'$clean_cuts'(G,G).
51
52'$clean_cuts'(!,_,true):- '$clean_cuts'.
53'$clean_cuts'(G,DCP,NG) :-
54 '$conj_has_cuts'(G,DCP,NG,OK), OK == '$conj_has_cuts', '$conj_has_cuts'.
55'$clean_cuts'(G,_,G).
56
57'$conj_has_cuts'(V,_,V, _) :- var(V), var.
58'$conj_has_cuts'(!,DCP,cut_by(DCP), ok) :- '$conj_has_cuts'.
59'$conj_has_cuts'((G1,G2),DCP,(NG1,NG2), OK) :- '$conj_has_cuts',
60 '$conj_has_cuts'(G1, DCP, NG1, OK),
61 '$conj_has_cuts'(G2, DCP, NG2, OK).
62'$conj_has_cuts'((G1;G2),DCP,(NG1;NG2), OK) :- '$conj_has_cuts',
63 '$conj_has_cuts'(G1, DCP, NG1, OK),
64 '$conj_has_cuts'(G2, DCP, NG2, OK).
65'$conj_has_cuts'((G1->G2),DCP,(NG1->G2), OK) :- '$conj_has_cuts',
66 % G1: the system must have done it already
67 '$conj_has_cuts'(G1, DCP, NG1, OK).
68'$conj_has_cuts'((G1*->G2),DCP,(NG1,G2), OK) :- '$conj_has_cuts',
69 % G1: the system must have done it already
70 '$conj_has_cuts'(G1, DCP, NG1, OK).
71'$conj_has_cuts'(if(G1,G2,G3),DCP,if(NG1,G2,G3), OK) :- '$conj_has_cuts',
72 % G1: the system must have done it already
73 '$conj_has_cuts'(G1, DCP, NG1, OK).
74'$conj_has_cuts'(G,_,G, _).
75
76% return list of vars in expanded positions on the head of a clause.
77%
78% these variables should not be expanded by meta-calls in the body of the goal.
79%
80% should be defined before caller.
81%
82'$module_u_vars'(M, H, UVars) :-
83 '$do_module_u_vars'(M:H,UVars).
84
85'$do_module_u_vars'(M:H,UVars) :-
86 functor(H,F,N),
87 functor(D,F,N),
88 (recorded('$m',meta_predicate(M,D),_)->recorded; recorded('$m',meta_predicate(prolog,D),_)), !,
89 '$do_module_u_vars'(N,D,H,UVars).
90'$do_module_u_vars'(_,[]).
91
92'$do_module_u_vars'(0,_,_,[]) :- '$do_module_u_vars'.
93'$do_module_u_vars'(I,D,H,LF) :-
94 arg(I,D,X), ( X=':' -> true ; integer(X)),
95 arg(I,H,A), '$uvar'(A, LF, L), '$uvar',
96 I1 is I-1,
97 '$do_module_u_vars'(I1,D,H,L).
98'$do_module_u_vars'(I,D,H,L) :-
99 I1 is I-1,
100 '$do_module_u_vars'(I1,D,H,L).
101
102'$uvar'(Y, [Y|L], L) :- var(Y), var.
103% support all/3
104'$uvar'(same( G, _), LF, L) :-
105 '$uvar'(G, LF, L).
106'$uvar'('^'( _, G), LF, L) :-
107 '$uvar'(G, LF, L).
108
109'$expand_args'([], _, [], _, []).
110'$expand_args'([A|GArgs], SM, [':'|GDefs], HVars, [NMA|NGArgs]) :-
111 '$expand_args',
112 (
113 lists:identical_member(A, HVars)
114 ->
115 A= NMA
116 ;
117 '$yap_strip_module'(SM:A,NM,NA),
118 NMA = NM:NA
119 ),
120 '$expand_args'(GArgs, SM, GDefs, HVars, NGArgs).
121'$expand_args'([A|GArgs], SM, [N|GDefs], HVars, [NA|NGArgs]) :-
122 number(N),
123 number,
124 (
125 lists:identical_member(A, HVars)
126 ->
127 A= NA
128 ;
129 var(A)
130 ->
131 NA = call(SM:A)
132 ;
133 A=call(GG)
134 ->
135 '$expand_args'([GG], SM, [0], HVars, [NA])
136;
137 A=V^IA
138 ->
139 NA = V^JA,
140 '$expand_args'([IA], SM, [N], HVars, [JA])
141 ;
142 '$expand_goals'(A, NA, _, SM, SM, SM, HVars-t)
143 ),
144 '$expand_args'(GArgs, SM, GDefs, HVars, NGArgs).
145'$expand_args'([A|GArgs], SM, [_N|GDefs], HVars, [A|NGArgs]) :-
146 '$expand_args'(GArgs, SM, GDefs, HVars, NGArgs).
147
148% expand module names in a body
149% args are:
150% goals to expand
151% code to pass to listing
152% code to pass to compiler
153% head module HM
154% source module SM
155% current module for looking up preds M
156%
157% to understand the differences, you can consider:
158%
159% a:(d:b(X)) :- g:c(X), d(X), user:hello(X)).
160%
161% when we process meta-predicate c, HM=d, DM=a, BM=a, M=g and we should get:
162%
163% d:b(X) :- g:c(g:X), a:d(X), user:hello(X).
164%
165% on the other hand,
166%
167% a:(d:b(X) :- c(X), d(X), d:e(X)).
168%
169% will give
170%
171% d:b(X) :- a:c(a:X), a:d(X), e(X).
172%
173%
174% head variab'$expand_goals'(M:G,G1,GO,HM,SM,,_M,HVars)les.
175% goals or arguments/sub-arguments?
176% I cannot use call here because of format/3
177% modules:
178% A4: module for body of clause (this is the one used in looking up predicates)
179% A5: context module (this is the current context
180 % A6: head module (this is the one used in compiling and accessing).
181%
182'$expand_goals'(V,call(BM:V),call(BM:V),_HM,_SM,BM,_HVarsH) :-
183 var(V),var.
184'$expand_goals'(BM:G,call(BM:G),call(BM:G),_HM,_SM,_,_HVarsH) :-
185 var(BM),
186 var.
187'$expand_goals'(BM:G,call(BM:G),call(BM:G),_HM,_SM,_BM0,_HVarsH) :-
188 var(G),
189 var.
190'$expand_goals'((A*->B;C),(A1*->B1;C1),(AO*->BO;CO),
191 HM,SM,BM,HVars) :- '$expand_goals',
192 '$expand_goals'(A,A1,AOO,HM,SM,BM,HVars),
193 '$clean_cuts'(AOO, AO),
194 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars),
195 '$expand_goals'(C,C1,CO,HM,SM,BM,HVars).
196'$expand_goals'((A->B;C),(A1->B1;C1),
197 (AO->BO;CO),
198 HM,SM,BM,HVars) :- '$expand_goals',
199 '$expand_goals'(A,A1,AOO,HM,SM,BM,HVars),
200 '$clean_cuts'(AOO, AO),
201 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars),
202 '$expand_goals'(C,C1,CO,HM,SM,BM,HVars).
203'$expand_goals'(if(A,B,C),if(A1,B1,C1),
204 (current_choice_point(CP0),
205 (current_choice_point(CP),AO,cut_at(CP0,CP),BO; CO)),HM,SM,BM,HVars) :- '$expand_goals',
206 '$expand_goals'(A,A1,AO0,HM,SM,BM,HVars),
207 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars),
208 '$expand_goals'(C,C1,CO,HM,SM,BM,HVars),
209 '$clean_cuts'(AO0, CP, AO).
210'$expand_goals'((A,B),(A1,B1),(AO,BO),HM,SM,BM,HVars) :- '$expand_goals',
211 '$expand_goals'(A,A1,AO,HM,SM,BM,HVars),
212 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars).
213'$expand_goals'((A;B),(A1;B1),(AO;BO),HM,SM,BM,HVars) :- var(A), var,
214 '$expand_goals'(A,A1,AO,HM,SM,BM,HVars),
215 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars).
216'$expand_goals'((A|B),(A1|B1),(AO|BO),HM,SM,BM,HVars) :- '$expand_goals',
217 '$expand_goals'(A,A1,AO,HM,SM,BM,HVars),
218 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars).
219'$expand_goals'((A->B),(A1->B1),( AO-> BO),HM,SM,BM,HVars) :- '$expand_goals',
220 '$expand_goals'(A,A1,AOO,HM,SM,BM,HVars),
221 '$clean_cuts'(AOO, AO),
222 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars).
223'$expand_goals'(\+G,\+G,A\=B,_HM,_BM,_SM,_HVars) :-
224 nonvar(G),
225 G = (A = B),
226 .
227'$expand_goals'(\+A,\+A1,(AO-> fail;true),HM,SM,BM,HVars) :- '$expand_goals',
228 '$expand_goals'(A,A1,AOO,HM,SM,BM,HVars),
229 '$clean_cuts'(AOO, AO).
230'$expand_goals'(once(A),once(A1),
231 (AO->true),HM,SM,BM,HVars) :- '$expand_goals',
232 '$expand_goals'(A,A1,AO0,HM,SM,BM,HVars),
233 '$clean_cuts'(AO0,AO).
234'$expand_goals'((:-A),(:-A1),
235 (:-AO),HM,SM,BM,HVars) :- '$expand_goals',
236 '$expand_goals'(A,A1,AO,HM,SM,BM,HVars).
237'$expand_goals'(ignore(A),ignore(A1),
238 (AO-> true ; true),HM,SM,BM,HVars) :- '$expand_goals',
239 '$expand_goals'(A,A1,AO0,HM,SM,BM,HVars),
240 '$clean_cuts'(AO0, AO).
241'$expand_goals'(forall(A,B),forall(A1,B1),
242 \+( (AO,\+ ( BO ) )),
243 HM,SM,BM,HVars) :- '$expand_goals',
244 '$expand_goals'(A,A1,AO0,HM,SM,BM,HVars),
245 '$expand_goals'(B,B1,BO0,HM,SM,BM,HVars),
246 '$clean_cuts'(AO0, AO),
247 '$clean_cuts'(BO0, BO).
248'$expand_goals'(not(A),not(A1),(current_choice_point(CP),AO,cut_by(CP) -> fail; true),HM,SM,BM,HVars) :- '$expand_goals',
249 '$expand_goals'(A,A1,AO,HM,SM,BM,HVars).
250'$expand_goals'((A*->B),(A1*->B1),(AO,BO),HM,SM,BM,HVars) :- '$expand_goals',
251 '$expand_goals'(A,A1,AO0,HM,SM,BM,HVars),
252 '$expand_goals'(B,B1,BO,HM,SM,BM,HVars),
253 '$clean_cuts'(AO0, AO).
254'$expand_goals'(true,true,true,_,_,_,_) :- '$expand_goals'.
255'$expand_goals'(fail,fail,fail,_,_,_,_) :- '$expand_goals'.
256'$expand_goals'(false,false,false,_,_,_,_) :- '$expand_goals'.
257'$expand_goals'(G, G1, GO, HM, SM, BM, HVars) :-
258 '$yap_strip_module'(BM:G, NBM, GM),
259 '$expand_goal'(GM, G1, GO, HM, SM, NBM, HVars).
260
261
262'$import_expansion'(M:G, M1:G1) :-
263 '$imported_predicate'(G, M, G1, M1),
264 '$imported_predicate'.
265'$import_expansion'(MG, MG).
266
267'$meta_expansion'(G, _GM, _SG, SM, _HVars, OG) :-
268 var(G),
269 var,
270 OG = call(SM:G).
271'$meta_expansion'(G, GM, _SG, SM, HVars, OG) :-
272 functor(G, F, Arity ),
273 functor(PredDef, F, Arity ),
274 (recorded('$m',meta_predicate(GM,PredDef),_)
275 ->recorded;recorded('$m',meta_predicate(prolog,PredDef),_)),
276 !,
277 G =.. [F|LArgs],
278 PredDef =.. [F|LMs],
279 '$expand_args'(LArgs, SM, LMs, HVars, OArgs),
280 OG =.. [F|OArgs].
281
282
283'$meta_expansion'(G, _GM, _SG, _SM, _HVars, G).
284
285 /**
286 * @brief Perform meta-variable and user expansion on a goal _G_
287 *
288 * given the example
289```
290:- module(m, []).
291
292o:p(B) :- n:g, X is 2+3, call(B).
293```
294 *
295 * @param G input goal, without module quantification.
296 * @param G1F output, non-optimised for debugging
297 * @param GOF output, optimised, ie, `n:g`, `prolog:(X is 2+3)`, `call(m:B)`, where `prolog` does not need to be explicit
298 * @param GOF output, optimised, `n:g`, `prolog:(X=5)`, `call(m:B)`
299 * @param HM head module, input, o
300 * @param HM source module, input, m
301 * @param M current module, input, `n`, `m`, `m`
302 * @param HVars-H, list of meta-variables and initial head, `[]` and `p(B)`
303 *
304 *
305 */
306 '$expand_goal'(G0, G1F, GOF, HM, SM0, BM0, HVars-H) :-
307 % we have a context
308 '$yap_strip_module'( BM0:G0, M0N, G), % MON is both the source and goal module
309 (G == G0 % use the environments SM and HM
310 ->
311 BM0 = BM, SM0 = SM
312 ;
313 % use the one(s) given by the user
314 M0N = BM, M0N= SM),
315 % we still may be using an imported predicate:
316
317 '$user_expansion'(BM:G, M1:G1),
318 '$import_expansion'(M1:G1, M2:G2),
319 '$meta_expansion'(G2, M2, G1, M1, HVars, G3),
320 '$match_mod'(G3, HM, SM, M2, G1F),
321 '$c_built_in'(G1F, M2, H, GOF).
322
323'$user_expansion'(M0N:G0N, M1:G1) :-
324 '_user_expand_goal'(M0N:G0N, M:G),
325 '_user_expand_goal',
326 ( M:G == M0N:G0N
327 ->
328 M1:G1 = M:G
329 ;
330 '$user_expansion'(M:G, M1:G1)
331 ).
332'$user_expansion'(MG, MG).
333
334'$match_mod'(G, HMod, SMod, M, O) :-
335 (
336 '$is_metapredicate'(G,M)
337 ->
338 O = M:G
339 ;
340 '$is_system_predicate'(G,prolog)
341 ->
342 O = G
343 ;
344 '$is_system_predicate' == HMod, '$is_system_predicate' == SMod, '$is_system_predicate' == M
345 ->
346 O = G
347 ;
348 O = M:G
349 ).
350
351'$build_up'(HM, NH, SM, true, NH, true, NH) :- HM == SM, '$build_up'.
352'$build_up'(HM, NH, _SM, true, HM:NH, true, HM:NH) :- '$build_up'.
353'$build_up'(HM, NH, SM, B1, (NH :- B1), BO, ( NH :- BO)) :- HM == SM, '$build_up'.
354'$build_up'(HM, NH, _SM, B1, (NH :- B1), BO, ( HM:NH :- BO)) :- '$build_up'.
355
356'$expand_goals'(BM:G,H,HM,_SM,_BM,B1,BO) :-
357 '$yap_strip_module'( BM:G, CM, G1),
358 '$yap_strip_module',
359 (var(CM) ->
360 '$expand_goals'(call(BM:G),H,HM,_SM,_BM,B1,BO)
361 ;
362 '$expand_goals'(G1,H,HM,CM,CM,B1,BO)
363 ).
364
365'$expand_clause_body'(V, _NH1, _HM1, _SM, M, call(M:V), call(M:V) ) :-
366 var(V), var.
367'$expand_clause_body'(true, _NH1, _HM1, _SM, _M, true, true ) :- '$expand_clause_body'.
368'$expand_clause_body'(B, H, HM, SM, M, B1, BO ) :-
369 '$module_u_vars'(HM , H, UVars),
370 % collect head variables in
371 % expanded positions
372 % support for SWI's meta primitive.
373 (
374 '$is_mt'(H, B, HM, SM, M, IB, BM)
375 ->
376 IB = B1, IB = BO0
377 ;
378 M = BM, '$expand_goals'(B, B1, BO0, HM, SM, BM, UVars-H)
379 ),
380 (
381 '$full_clause_optimisation'(H, BM, BO0, BO)
382 ->
383 '$full_clause_optimisation'
384 ;
385 BO = BO0
386 ).
387
388%
389% check if current module redefines an imported predicate.
390% and remove import.
391%
392'$not_imported'(H, Mod) :-
393 recorded('$import','$import'(NM,Mod,NH,H,_,_),R),
394 NM \= Mod,
395 functor(NH,N,Ar),
396 print_message(warning,redefine_imported(Mod,NM,N/Ar)),
397 erase(R),
398 erase.
399'$not_imported'(_, _).
400
401
402'$verify_import'(M:G, NM:NG) :-
403 '$follow_import_chain'(M,G,NM,NG).
404
405
406'$expand_meta_call'(M0:G, HVars, M:GF ) :-
407 '$expand_meta_call',
408 '$yap_strip_module'(M0:G, M, IG),
409 '$expand_goals'(IG, GF, _GF0, M, M, M, HVars-IG).
410'$expand_meta_call'(G, HVars, M:GF ) :-
411 source_module(SM0),
412 '$yap_strip_module'(SM0:G, M, IG),
413 '$expand_goals'(IG, GF, _GF0, SM, SM, M, HVars-IG).
414
415
416'$expand_a_clause'(MHB, SM0, Cl1, ClO) :- % MHB is the original clause, SM0 the current source, Cl1 and ClO output clauses
417 '$yap_strip_module'(SM0:MHB, SM, HB), % remove layers of modules over the clause. SM is the source module.
418 '$head_and_body'(HB, H, B), % HB is H :- B.
419 '$yap_strip_module'(SM:H, HM, NH), % further module expansion
420 '$not_imported'(NH, HM),
421 '$yap_strip_module'(SM:B, BM, B0), % further module expansion
422 '$expand_clause_body'(B0, NH, HM, SM0, BM, B1, BO),
423 '$expand_clause_body',
424 '$build_up'(HM, NH, SM0, B1, Cl1, BO, ClO).
425'$expand_a_clause'(Cl, _SM, Cl, Cl).
426
427
428
429
430% expand arguments of a meta-predicate
431% $meta_expansion(ModuleWhereDefined,CurrentModule,Goal,ExpandedGoal,MetaVariables)
432
433
434% expand module names in a clause (interface predicate).
435% A1: Input Clause
436% A2: Output Class to Compiler (lives in module HM)
437% A3: Output Class to clause/2 and listing (lives in module HM)
438%
439% modules:
440% A6: head module (this is the one used in compiling and accessing).
441% A5: context module (this is the current context
442% A4: module for body of clause (this is the one used in looking up predicates)
443%
444 % has to be last!!!
445expand_goal(Input, Output) :-
446 '$expand_meta_call'(Input, [], Output ).
source_module(-Mod)
erase(+ R)
call( 0:P )
print_message(+ Severity, +Term)
arg(+ N,+ T, A)
functor( T, F, N)
integer( T)
nonvar( T)
number( T)
var( T)
identical_member(?Element, ?Set)