36
37:- module(apply_macros,
38 [ expand_phrase/2, 39 expand_phrase/4 40 ]). 42:- use_module(library(apply), [maplist/2, maplist/3, maplist/4]). 44:- autoload(library(error),[type_error/2]). 45:- autoload(library(lists),[append/3]). 46:- autoload(library(prolog_code), [mkconj/3, extend_goal/3]). 47:- autoload(library(yall), [is_lambda/1, lambda_calls/3]). 48
73
74:- dynamic
75 user:goal_expansion/2. 76:- multifile
77 user:goal_expansion/2. 78
79
88
89expand_maplist(Callable, Lists, Goal) :-
90 maplist(is_list, Lists),
91 maplist(length, Lists, Lens),
92 ( sort(Lens, [Len])
93 -> Len < 10,
94 unfold_maplist(Lists, Callable, Goal),
95 !
96 ; Maplist =.. [maplist,Callable|Lists],
97 print_message(warning, maplist(inconsistent_length(Maplist, Lens))),
98 fail
99 ).
100expand_maplist(Callable0, Lists, Goal) :-
101 length(Lists, N),
102 expand_closure_no_fail(Callable0, N, Callable1),
103 ( Callable1 = _:_
104 -> strip_module(Callable1, M, Callable),
105 NextGoal = M:NextCall,
106 QPred = M:Pred
107 ; Callable = Callable1,
108 NextGoal = NextCall,
109 QPred = Pred
110 ),
111 Callable =.. [Pred|Args],
112 length(Args, Argc),
113 length(Argv, Argc),
114 length(Vars, N),
115 MapArity is N + 1,
116 format(atom(AuxName), '__aux_maplist/~d_~w+~d', [MapArity, QPred, Argc]),
117 append(Lists, Args, AuxArgs),
118 Goal =.. [AuxName|AuxArgs],
119
120 AuxArity is N+Argc,
121 prolog_load_context(module, Module),
122 functor(NextCall, Pred, AuxArity),
123 \+ predicate_property(Module:NextGoal, transparent),
124 ( predicate_property(Module:Goal, defined)
125 -> true
126 ; empty_lists(N, BaseLists),
127 length(Anon, Argc),
128 append(BaseLists, Anon, BaseArgs),
129 BaseClause =.. [AuxName|BaseArgs],
130
131 heads_and_tails(N, NextArgs, Vars, Tails),
132 append(NextArgs, Argv, AllNextArgs),
133 NextHead =.. [AuxName|AllNextArgs],
134 append(Argv, Vars, PredArgs),
135 NextCall =.. [Pred|PredArgs],
136 append(Tails, Argv, IttArgs),
137 NextIterate =.. [AuxName|IttArgs],
138 NextClause = (NextHead :- NextGoal, NextIterate),
139 compile_aux_clauses([BaseClause, NextClause])
140 ).
141
142unfold_maplist(Lists, Callable, Goal) :-
143 maplist(cons, Lists, Heads, Tails),
144 !,
145 maplist_extend_goal(Callable, Heads, G1),
146 unfold_maplist(Tails, Callable, G2),
147 mkconj(G1, G2, Goal).
148unfold_maplist(_, _, true).
149
150cons([H|T], H, T).
151
159
160maplist_extend_goal(Closure, Args, Goal) :-
161 is_lambda(Closure),
162 !,
163 lambda_calls(Closure, Args, Goal1),
164 expand_goal_no_instantiate(Goal1, Goal).
165maplist_extend_goal(Closure, Args, Goal) :-
166 extend_goal(Closure, Args, Goal1),
167 expand_goal_no_instantiate(Goal1, Goal).
168
171
172expand_goal_no_instantiate(Goal0, Goal) :-
173 term_variables(Goal0, Vars0),
174 expand_goal(Goal0, Goal),
175 term_variables(Goal0, Vars1),
176 Vars0 == Vars1.
177
181
182expand_closure_no_fail(Callable0, N, Callable1) :-
183 '$expand_closure'(Callable0, N, Callable1),
184 !.
185expand_closure_no_fail(Callable, _, Callable).
186
187empty_lists(0, []) :- !.
188empty_lists(N, [[]|T]) :-
189 N2 is N - 1,
190 empty_lists(N2, T).
191
192heads_and_tails(0, [], [], []).
193heads_and_tails(N, [[H|T]|L1], [H|L2], [T|L3]) :-
194 N2 is N - 1,
195 heads_and_tails(N2, L1, L2, L3).
196
197
201
202expand_apply(Maplist, Goal) :-
203 compound(Maplist),
204 compound_name_arity(Maplist, maplist, N),
205 N >= 2,
206 Maplist =.. [maplist, Callable|Lists],
207 qcall_instantiated(Callable),
208 !,
209 expand_maplist(Callable, Lists, Goal).
210
220
221expand_apply(forall(Cond, Action), Pos0, Goal, Pos) :-
222 Goal = \+((Cond, \+(Action))),
223 ( nonvar(Pos0),
224 Pos0 = term_position(_,_,_,_,[PosCond,PosAct])
225 -> Pos = term_position(0,0,0,0, 226 [ term_position(0,0,0,0, 227 [ PosCond,
228 term_position(0,0,0,0, 229 [PosAct])
230 ])
231 ])
232 ; true
233 ).
234expand_apply(once(Once), Pos0, Goal, Pos) :-
235 Goal = (Once->true),
236 ( nonvar(Pos0),
237 Pos0 = term_position(_,_,_,_,[OncePos]),
238 compound(OncePos)
239 -> Pos = term_position(0,0,0,0, 240 [ OncePos,
241 F-T 242 ]),
243 arg(2, OncePos, F), 244 T is F+1
245 ; true
246 ).
247expand_apply(ignore(Ignore), Pos0, Goal, Pos) :-
248 Goal = (Ignore->true;true),
249 ( nonvar(Pos0),
250 Pos0 = term_position(_,_,_,_,[IgnorePos]),
251 compound(IgnorePos)
252 -> Pos = term_position(0,0,0,0, 253 [ term_position(0,0,0,0, 254 [ IgnorePos,
255 F-T 256 ]),
257 F-T 258 ]),
259 arg(2, IgnorePos, F), 260 T is F+1
261 ; true
262 ).
263expand_apply(Phrase, Pos0, Expanded, Pos) :-
264 expand_phrase(Phrase, Pos0, Expanded, Pos),
265 !.
266
267
284
285expand_phrase(Phrase, Goal) :-
286 expand_phrase(Phrase, _, Goal, _).
287
288expand_phrase(phrase(NT,Xs), Pos0, NTXsNil, Pos) :-
289 !,
290 extend_pos(Pos0, 1, Pos1),
291 expand_phrase(phrase(NT,Xs,[]), Pos1, NTXsNil, Pos).
292expand_phrase(Goal, Pos0, NewGoal, Pos) :-
293 dcg_goal(Goal, NT, Xs0, Xs),
294 nonvar(NT),
295 nt_pos(Pos0, NTPos),
296 dcg_extend(NT, NTPos, NewGoal, Pos, Xs0, Xs).
297
298dcg_goal(phrase(NT,Xs0,Xs), NT, Xs0, Xs).
299dcg_goal(call_dcg(NT,Xs0,Xs), NT, Xs0, Xs).
300
302
303dcg_extend(Compound0, Pos0, Compound, Pos, Xs0, Xs) :-
304 compound(Compound0),
305 \+ dcg_control(Compound0),
306 !,
307 extend_pos(Pos0, 2, Pos),
308 compound_name_arguments(Compound0, Name, Args0),
309 append(Args0, [Xs0,Xs], Args),
310 compound_name_arguments(Compound, Name, Args).
311dcg_extend(Name, Pos0, Compound, Pos, Xs0, Xs) :-
312 atom(Name),
313 \+ dcg_control(Name),
314 !,
315 extend_pos(Pos0, 2, Pos),
316 compound_name_arguments(Compound, Name, [Xs0,Xs]).
317dcg_extend(Q0, Pos0, M:Q, Pos, Xs0, Xs) :-
318 compound(Q0), Q0 = M:Q1,
319 '$expand':f2_pos(Pos0, MPos, APos0, Pos, MPos, APos),
320 dcg_extend(Q1, APos0, Q, APos, Xs0, Xs).
321dcg_extend(Terminal, Pos0, Xs0 = DList, Pos, Xs0, Xs) :-
322 terminal(Terminal, DList, Xs),
323 !,
324 t_pos(Pos0, Pos).
325
326dcg_control(!).
327dcg_control([]).
328dcg_control([_|_]).
329dcg_control({_}).
330dcg_control((_,_)).
331dcg_control((_;_)).
332dcg_control((_->_)).
333dcg_control((_*->_)).
334dcg_control(_:_).
335
336terminal(List, DList, Tail) :-
337 compound(List),
338 List = [_|_],
339 !,
340 '$skip_list'(_, List, T0),
341 ( var(T0)
342 -> DList = List,
343 Tail = T0
344 ; T0 == []
345 -> append(List, Tail, DList)
346 ; type_error(list, List)
347 ).
348terminal(List, DList, Tail) :-
349 List == [],
350 !,
351 DList = Tail.
352terminal(String, DList, Tail) :-
353 string(String),
354 string_codes(String, List),
355 append(List, Tail, DList).
356
357extend_pos(Var, _, Var) :-
358 var(Var),
359 !.
360extend_pos(term_position(F,T,FF,FT,ArgPos0), Extra,
361 term_position(F,T,FF,FT,ArgPos)) :-
362 !,
363 extra_pos(Extra, T, ExtraPos),
364 append(ArgPos0, ExtraPos, ArgPos).
365extend_pos(FF-FT, Extra,
366 term_position(FF,FT,FF,FT,ArgPos)) :-
367 !,
368 extra_pos(Extra, FT, ArgPos).
369
(1, T, [T-T]).
371extra_pos(2, T, [T-T,T-T]).
372
373nt_pos(PhrasePos, _NTPos) :-
374 var(PhrasePos),
375 !.
376nt_pos(term_position(_,_,_,_,[NTPos|_]), NTPos).
377
378t_pos(Pos0, term_position(F,T,F,T,[F-T,F-T])) :-
379 compound(Pos0),
380 !,
381 arg(1, Pos0, F),
382 arg(2, Pos0, T).
383t_pos(_, _).
384
385
391
392qcall_instantiated(Var) :-
393 var(Var),
394 !,
395 fail.
396qcall_instantiated(M:C) :-
397 !,
398 atom(M),
399 callable(C).
400qcall_instantiated(C) :-
401 callable(C).
402
403
404 407
408:- multifile
409 prolog_clause:unify_goal/5. 410
411prolog_clause:unify_goal(Maplist, Expanded, _Module, Pos0, Pos) :-
412 is_maplist(Maplist),
413 maplist_expansion(Expanded),
414 Pos0 = term_position(F,T,FF,FT,[_MapPos|ArgsPos]),
415 Pos = term_position(F,T,FF,FT,ArgsPos).
416
417is_maplist(Goal) :-
418 compound(Goal),
419 compound_name_arity(Goal, maplist, A),
420 A >= 2.
421
422maplist_expansion(Expanded) :-
423 compound(Expanded),
424 compound_name_arity(Expanded, Name, _),
425 sub_atom(Name, 0, _, _, '__aux_maplist/').
426
427
428 431
432:- multifile
433 prolog_colour:vararg_goal_classification/3. 434
435prolog_colour:vararg_goal_classification(maplist, Arity, expanded) :-
436 Arity >= 2.
437
438
439 442
443:- multifile
444 system:goal_expansion/2,
445 system:goal_expansion/4. 446
448
449system:goal_expansion(GoalIn, GoalOut) :-
450 \+ current_prolog_flag(xref, true),
451 expand_apply(GoalIn, GoalOut).
452system:goal_expansion(GoalIn, PosIn, GoalOut, PosOut) :-
453 expand_apply(GoalIn, PosIn, GoalOut, PosOut).
454
455 458
459:- multifile
460 prolog:message//1. 461
462prolog:message(maplist(inconsistent_length(Maplist, Lens))) -->
463 { functor(Maplist, _, N) },
464 [ 'maplist/~d called with proper lists of different lengths (~p) always fails'
465 -[N, Lens] ]