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(Terminal, Pos0, Xs0 = DList, Pos, Xs0, Xs) :-
304 terminal(Terminal, DList, Xs),
305 !,
306 t_pos(Pos0, Pos).
307dcg_extend(Q0, Pos0, M:Q, Pos, Xs0, Xs) :-
308 nonvar(Q0), Q0 = M:Q1,
309 !,
310 '$expand':f2_pos(Pos0, MPos, APos0, Pos, MPos, APos),
311 dcg_extend(Q1, APos0, Q, APos, Xs0, Xs).
312dcg_extend(Control, _, _, _, _, _) :-
313 dcg_control(Control),
314 !,
315 fail.
316dcg_extend(Compound0, Pos0, Compound, Pos, Xs0, Xs) :-
317 compound(Compound0),
318 !,
319 extend_pos(Pos0, 2, Pos),
320 compound_name_arguments(Compound0, Name, Args0),
321 append(Args0, [Xs0,Xs], Args),
322 compound_name_arguments(Compound, Name, Args).
323dcg_extend(Name, Pos0, Compound, Pos, Xs0, Xs) :-
324 atom(Name),
325 !,
326 extend_pos(Pos0, 2, Pos),
327 compound_name_arguments(Compound, Name, [Xs0,Xs]).
328
329dcg_control(!).
330dcg_control([]).
331dcg_control([_|_]).
332dcg_control({_}).
333dcg_control((_,_)).
334dcg_control((_;_)).
335dcg_control((_->_)).
336dcg_control((_*->_)).
337
338terminal([], DList, Tail) =>
339 DList = Tail.
340terminal(String, DList, Tail), string(String) =>
341 string(String),
342 string_codes(String, List),
343 append(List, Tail, DList).
344terminal(List, DList, Tail), is_list(List) =>
345 append(List, Tail, DList).
346terminal(_, _, _) =>
347 fail.
348
349extend_pos(Var, _, Var) :-
350 var(Var),
351 !.
352extend_pos(term_position(F,T,FF,FT,ArgPos0), Extra,
353 term_position(F,T,FF,FT,ArgPos)) :-
354 !,
355 extra_pos(Extra, T, ExtraPos),
356 append(ArgPos0, ExtraPos, ArgPos).
357extend_pos(FF-FT, Extra,
358 term_position(FF,FT,FF,FT,ArgPos)) :-
359 !,
360 extra_pos(Extra, FT, ArgPos).
361
(1, T, [T-T]).
363extra_pos(2, T, [T-T,T-T]).
364
365nt_pos(PhrasePos, _NTPos) :-
366 var(PhrasePos),
367 !.
368nt_pos(term_position(_,_,_,_,[NTPos|_]), NTPos).
369
370t_pos(Pos0, term_position(F,T,F,T,[F-T,F-T])) :-
371 compound(Pos0),
372 !,
373 arg(1, Pos0, F),
374 arg(2, Pos0, T).
375t_pos(_, _).
376
377
383
384qcall_instantiated(Var) :-
385 var(Var),
386 !,
387 fail.
388qcall_instantiated(M:C) :-
389 !,
390 atom(M),
391 callable(C).
392qcall_instantiated(C) :-
393 callable(C).
394
395
396 399
400:- multifile
401 prolog_clause:unify_goal/5. 402
403prolog_clause:unify_goal(Maplist, Expanded, _Module, Pos0, Pos) :-
404 is_maplist(Maplist),
405 maplist_expansion(Expanded),
406 Pos0 = term_position(F,T,FF,FT,[_MapPos|ArgsPos]),
407 Pos = term_position(F,T,FF,FT,ArgsPos).
408
409is_maplist(Goal) :-
410 compound(Goal),
411 compound_name_arity(Goal, maplist, A),
412 A >= 2.
413
414maplist_expansion(Expanded) :-
415 compound(Expanded),
416 compound_name_arity(Expanded, Name, _),
417 sub_atom(Name, 0, _, _, '__aux_maplist/').
418
419
420 423
424:- multifile
425 prolog_colour:vararg_goal_classification/3. 426
427prolog_colour:vararg_goal_classification(maplist, Arity, expanded) :-
428 Arity >= 2.
429
430
431 434
435:- multifile
436 system:goal_expansion/2,
437 system:goal_expansion/4. 438
440
441system:goal_expansion(GoalIn, GoalOut) :-
442 \+ current_prolog_flag(xref, true),
443 expand_apply(GoalIn, GoalOut).
444system:goal_expansion(GoalIn, PosIn, GoalOut, PosOut) :-
445 expand_apply(GoalIn, PosIn, GoalOut, PosOut).
446
447 450
451:- multifile
452 prolog:message//1. 453
454prolog:message(maplist(inconsistent_length(Maplist, Lens))) -->
455 { functor(Maplist, _, N) },
456 [ 'maplist/~d called with proper lists of different lengths (~p) always fails'
457 -[N, Lens] ]