34
35:- module('$dwim',
36 [ dwim_predicate/2,
37 '$dwim_correct_goal'/3,
38 '$find_predicate'/2,
39 '$similar_module'/2
40 ]). 41
42:- meta_predicate
43 dwim_predicate(:, -),
44 '$dwim_correct_goal'(:, +, -),
45 '$similar_module'(:, -),
46 '$find_predicate'(:, -). 47
56
57'$dwim_correct_goal'(M:Goal, Bindings, Corrected) :-
58 correct_goal(Goal, M, Bindings, Corrected).
59
60correct_goal(Goal, M, _, M:Goal) :-
61 var(Goal),
62 !.
63correct_goal(Module:Goal, _, _, Module:Goal) :-
64 ( var(Module)
65 ; var(Goal)
66 ),
67 !.
68correct_goal(Vars^Goal0, M, Bindings, Vars^Goal) :- 69 !,
70 correct_goal(Goal0, M, Bindings, Goal).
71correct_goal(Module:Goal0, _, Bindings, Module:Goal) :-
72 current_predicate(_, Module:Goal0),
73 !,
74 correct_meta_arguments(Goal0, Module, Bindings, Goal).
75correct_goal(Goal0, M, Bindings, M:Goal) :- 76 current_predicate(_, M:Goal0),
77 !,
78 correct_meta_arguments(Goal0, M, Bindings, Goal).
79correct_goal(Goal0, M, Bindings, Goal) :- 80 dwim_predicate_list(M:Goal0, DWIMs0),
81 !,
82 principal_predicates(DWIMs0, M, DWIMs),
83 correct_literal(M:Goal0, Bindings, DWIMs, Goal1),
84 correct_meta_arguments(Goal1, M, Bindings, Goal).
85correct_goal(Goal, Module, _, NewGoal) :- 86 \+ current_prolog_flag(Module:unknown, fail),
87 callable(Goal),
88 !,
89 callable_name_arity(Goal, Name, Arity),
90 '$undefined_procedure'(Module, Name, Arity, Action),
91 ( Action == error
92 -> existence_error(Module:Name/Arity),
93 NewGoal = fail
94 ; Action == retry
95 -> NewGoal = Goal
96 ; NewGoal = fail
97 ).
98correct_goal(Goal, M, _, M:Goal).
99
100callable_name_arity(Goal, Name, Arity) :-
101 compound(Goal),
102 !,
103 compound_name_arity(Goal, Name, Arity).
104callable_name_arity(Goal, Goal, 0) :-
105 atom(Goal).
106
107existence_error(PredSpec) :-
108 strip_module(PredSpec, M, _),
109 current_prolog_flag(M:unknown, Unknown),
110 dwim_existence_error(Unknown, PredSpec).
111
112dwim_existence_error(fail, _) :- !.
113dwim_existence_error(Unknown, PredSpec) :-
114 '$current_typein_module'(TypeIn),
115 unqualify_if_context(TypeIn, PredSpec, Spec),
116 ( no_context(Spec)
117 -> true
118 ; Context = context(toplevel, 'DWIM could not correct goal')
119 ),
120 Error = error(existence_error(procedure, Spec), Context),
121 ( Unknown == error
122 -> throw(Error)
123 ; print_message(warning, Error)
124 ).
125
130
131no_context((^)/2).
132no_context((:-)/2).
133no_context((:-)/1).
134no_context((?-)/1).
135
136
143
144correct_meta_arguments(call(Goal), _, _, call(Goal)) :- !.
145correct_meta_arguments(Goal0, M, Bindings, Goal) :-
146 predicate_property(M:Goal0, meta_predicate(MHead)),
147 !,
148 functor(Goal0, Name, Arity),
149 functor(Goal, Name, Arity),
150 correct_margs(0, Arity, MHead, Goal0, Goal, M, Bindings).
151correct_meta_arguments(Goal, _, _, Goal).
152
153correct_margs(Arity, Arity, _, _, _, _, _) :- !.
154correct_margs(A, Arity, MHead, GoalIn, GoalOut, M, Bindings) :-
155 I is A+1,
156 arg(I, GoalIn, Ain),
157 arg(I, GoalOut, AOut),
158 ( arg(I, MHead, 0)
159 -> correct_goal(Ain, M, Bindings, AOut0),
160 unqualify_if_context(M, AOut0, AOut)
161 ; AOut = Ain
162 ),
163 correct_margs(I, Arity, MHead, GoalIn, GoalOut, M, Bindings).
164
165
170
171correct_literal(Goal, Bindings, [Dwim], DwimGoal) :-
172 strip_module(Goal, CM, G1),
173 strip_module(Dwim, DM, G2),
174 callable_name_arity(G1, _, Arity),
175 callable_name_arity(G2, Name, Arity), 176 !,
177 change_functor_name(G1, Name, G2),
178 ( ( current_predicate(CM:Name/Arity)
179 -> ConfirmGoal = G2,
180 DwimGoal = CM:G2
181 ; '$prefix_module'(DM, CM, G2, ConfirmGoal),
182 DwimGoal = ConfirmGoal
183 ),
184 goal_name(ConfirmGoal, Bindings, String),
185 '$confirm'(dwim_correct(String))
186 -> true
187 ; DwimGoal = Goal
188 ).
189correct_literal(Goal, Bindings, Dwims, NewGoal) :-
190 strip_module(Goal, _, G1),
191 callable_name_arity(G1, _, Arity),
192 include_arity(Dwims, Arity, [Dwim]),
193 !,
194 correct_literal(Goal, Bindings, [Dwim], NewGoal).
195correct_literal(Goal, _, Dwims, _) :-
196 print_message(error, dwim_undefined(Goal, Dwims)),
197 fail.
198
199change_functor_name(Term1, Name2, Term2) :-
200 compound(Term1),
201 !,
202 compound_name_arguments(Term1, _, Arguments),
203 compound_name_arguments(Term2, Name2, Arguments).
204change_functor_name(Term1, Name2, Name2) :-
205 atom(Term1).
206
207include_arity([], _, []).
208include_arity([H|T0], Arity, [H|T]) :-
209 strip_module(H, _, G),
210 functor(G, _, Arity),
211 !,
212 include_arity(T0, Arity, T).
213include_arity([_|T0], Arity, T) :-
214 include_arity(T0, Arity, T).
215
216
220
221goal_name(Goal, Bindings, String) :-
222 State = s(_),
223 ( bind_vars(Bindings),
224 numbervars(Goal, 0, _, [singletons(true), attvar(skip)]),
225 format(string(S), '~q', [Goal]),
226 nb_setarg(1, State, S),
227 fail
228 ; arg(1, State, String)
229 ).
230
231bind_vars([]).
232bind_vars([Name=Var|T]) :-
233 Var = '$VAR'(Name), 234 !,
235 bind_vars(T).
236bind_vars([_|T]) :-
237 bind_vars(T).
238
239
251
252'$find_predicate'(M:S, List) :-
253 name_arity(S, Name, Arity),
254 '$current_typein_module'(TypeIn),
255 ( M == TypeIn, 256 \+ module_property(M, class(temporary))
257 -> true
258 ; Module = M
259 ),
260 find_predicate(Module, Name, Arity, L0),
261 !,
262 sort(L0, L1),
263 principal_pis(L1, Module, List).
264'$find_predicate'(_:S, List) :-
265 name_arity(S, Name, Arity),
266 findall(Name/Arity,
267 '$in_library'(Name, Arity, _Path), List),
268 List \== [],
269 !.
270'$find_predicate'(Spec, _) :-
271 existence_error(Spec),
272 fail.
273
274find_predicate(Module, Name, Arity, VList) :-
275 findall(Head, find_predicate_(Module, Name, Arity, Head), VList),
276 VList \== [],
277 !.
278find_predicate(Module, Name, Arity, Pack) :-
279 findall(PI, find_sim_pred(Module, Name, Arity, PI), List),
280 pack(List, Module, Arity, Packs),
281 '$member'(Dwim-Pack, Packs),
282 '$confirm'(dwim_correct(Dwim)),
283 !.
284
285unqualify_if_context(_, X, X) :-
286 var(X),
287 !.
288unqualify_if_context(C, C2:X, X) :-
289 C == C2,
290 !.
291unqualify_if_context(_, X, X) :- !.
292
297
298pack([], _, _, []) :- !.
299pack([M:T|Rest], Module, Arity, [Name-[M:T|R]|Packs]) :-
300 pack_name(M:T, Module, Arity, Name),
301 pack_(Module, Arity, Name, Rest, R, NewRest),
302 pack(NewRest, Module, Arity, Packs).
303
304pack_(Module, Arity, Name, List, [H|R], Rest) :-
305 '$select'(M:PI, List, R0),
306 pack_name(M:PI, Module, Arity, Name),
307 !,
308 '$prefix_module'(M, C, PI, H),
309 pack_(Module, Arity, Name, C, R0, R, Rest).
310pack_(_, _, _, _, Rest, [], Rest).
311
312pack_name(_:Name/_, M, A, Name) :-
313 var(M), var(A),
314 !.
315pack_name(M:Name/_, _, A, M:Name) :-
316 var(A),
317 !.
318pack_name(_:PI, M, _, PI) :-
319 var(M),
320 !.
321pack_name(QPI, _, _, QPI).
322
323
324find_predicate_(Module, Name, Arity, Module:Name/Arity) :-
325 current_module(Module),
326 current_predicate(Name, Module:Term),
327 functor(Term, Name, Arity).
328
329find_sim_pred(M, Name, Arity, Module:DName/DArity) :-
330 sim_module(M, Module),
331 '$dwim_predicate'(Module:Name, Term),
332 functor(Term, DName, DArity),
333 sim_arity(Arity, DArity).
334
335sim_module(M, Module) :-
336 var(M),
337 !,
338 current_module(Module).
339sim_module(M, M) :-
340 current_module(M),
341 !.
342sim_module(M, Module) :-
343 current_module(Module),
344 dwim_match(M, Module).
345
346sim_arity(A, _) :- var(A), !.
347sim_arity(A, D) :- abs(A-D) < 2.
348
353
354name_arity(Atom, Atom, _) :-
355 atom(Atom),
356 !.
357name_arity(Name/Arity, Name, Arity) :- !.
358name_arity(Name//DCGArity, Name, Arity) :-
359 ( var(DCGArity)
360 -> true
361 ; Arity is DCGArity+2
362 ).
363name_arity(Term, Name, Arity) :-
364 callable(Term),
365 !,
366 functor(Term, Name, Arity).
367name_arity(Spec, _, _) :-
368 throw(error(type_error(predicate_indicator, Spec), _)).
369
370
371principal_pis(PIS, M, Principals) :-
372 map_pi_heads(PIS, Heads),
373 principal_predicates(Heads, M, Heads2),
374 map_pi_heads(Principals, Heads2).
375
376map_pi_heads([], []) :- !.
377map_pi_heads([PI0|T0], [H0|T]) :-
378 map_pi_head(PI0, H0),
379 map_pi_heads(T0, T).
380
381map_pi_head(M:PI, M:Head) :-
382 nonvar(M),
383 !,
384 map_pi_head(PI, Head).
385map_pi_head(Name/Arity, Term) :-
386 functor(Term, Name, Arity).
387
392
393principal_predicates(Heads, M, Principals) :-
394 find_definitions(Heads, M, Heads2),
395 strip_subsumed_heads(Heads2, Principals).
396
397find_definitions([], _, []).
398find_definitions([H0|T0], M, [H|T]) :-
399 find_definition(H0, M, H),
400 find_definitions(T0, M, T).
401
402find_definition(Head, _, Def) :-
403 strip_module(Head, _, Plain),
404 callable(Plain),
405 ( predicate_property(Head, imported_from(Module))
406 -> ( predicate_property(system:Plain, imported_from(Module)),
407 sub_atom(Module, 0, _, _, $)
408 -> Def = system:Plain
409 ; Def = Module:Plain
410 )
411 ; Def = Head
412 ).
413
419
420strip_subsumed_heads([], []).
421strip_subsumed_heads([H|T0], T) :-
422 '$member'(H2, T0),
423 subsumes_term(H2, H),
424 \+ subsumes_term(H, H2),
425 !,
426 strip_subsumed_heads(T0, T).
427strip_subsumed_heads([H|T0], [H|T]) :-
428 strip_subsumed(T0, H, T1),
429 strip_subsumed_heads(T1, T).
430
431strip_subsumed([], _, []).
432strip_subsumed([H|T0], G, T) :-
433 subsumes_term(G, H),
434 !,
435 strip_subsumed(T0, G, T).
436strip_subsumed([H|T0], G, [H|T]) :-
437 strip_subsumed(T0, G, T).
438
439
448
449dwim_predicate(Head, DWIM) :-
450 dwim_predicate_list(Head, DWIMs),
451 '$member'(DWIM, DWIMs).
452
453dwim_predicate_list(Head, [Head]) :-
454 current_predicate(_, Head),
455 !.
456dwim_predicate_list(M:Head, DWIMs) :-
457 setof(DWIM, dwim_pred(M:Head, DWIM), DWIMs),
458 !.
459dwim_predicate_list(Head, DWIMs) :-
460 setof(DWIM, '$similar_module'(Head, DWIM), DWIMs),
461 !.
462dwim_predicate_list(_:Goal, DWIMs) :-
463 setof(Module:Goal,
464 current_predicate(_, Module:Goal),
465 DWIMs).
466
471
472dwim_pred(Head, M:Dwim) :-
473 strip_module(Head, Module, H),
474 default_module(Module, M),
475 '$dwim_predicate'(M:H, Dwim).
476
481
482'$similar_module'(Module:Goal, DwimModule:Goal) :-
483 current_module(DwimModule),
484 dwim_match(Module, DwimModule),
485 current_predicate(_, DwimModule:Goal)