1:- module(scasp_dyncall,
2 [ scasp/2, 3 scasp_query_clauses/2, 4 scasp_model/1, 5 scasp_justification/2, 6
7 scasp_show/2, 8
9 (scasp_dynamic)/1, 10 scasp_assert/1, 11 scasp_assert/2, 12 scasp_retract/1, 13 scasp_retractall/1, 14 scasp_abolish/1, 15 (#)/1, 16 (#)/2, 17 (pred)/1,
18 (show)/1,
19 (abducible)/1,
20 (abducible)/2,
21
22 (#=)/2,
23 (#<>)/2,
24 (#<)/2,
25 (#>)/2,
26 (#=<)/2,
27 (#>=)/2,
28
29 op(900, fy, not),
30 op(950, xfx, ::), 31 op(1200, fx, #),
32 op(1150, fx, pred),
33 op(1150, fx, show),
34 op(1150, fx, abducible),
35 op(1150, fx, scasp_dynamic),
36 op(700, xfx, #=),
37 op(700, xfx, #<>),
38 op(700, xfx, #<),
39 op(700, xfx, #>),
40 op(700, xfx, #=<),
41 op(700, xfx, #>=)
42 ]). 43:- use_module(compile). 44:- use_module(embed). 45:- use_module(common). 46:- use_module(modules). 47:- use_module(source_ref). 48:- use_module(listing). 49:- use_module(clp/clpq, [apply_clpq_constraints/1]). 50:- use_module(pr_rules, [process_pr_pred/5]). 51:- use_module(predicates, [prolog_builtin/1,
52 clp_builtin/1, clp_interval/1]). 53
54:- use_module(library(apply), [maplist/3, exclude/3, maplist/2]). 55:- use_module(library(assoc), [empty_assoc/1, get_assoc/3, put_assoc/4]). 56:- use_module(library(error),
57 [ instantiation_error/1,
58 permission_error/3,
59 type_error/2,
60 must_be/2
61 ]). 62:- use_module(library(lists), [member/2, append/3]). 63:- use_module(library(modules),
64 [in_temporary_module/3, current_temporary_module/1]). 65:- use_module(library(option), [option/2]). 66:- use_module(library(ordsets), [ord_intersect/2, ord_union/3]). 67:- use_module(library(prolog_code), [pi_head/2]). 68
69:- meta_predicate
70 scasp(0, +),
71 scasp_show(:, +),
72 scasp_query_clauses(:, -),
73 scasp_dynamic(:),
74 scasp_assert(:),
75 scasp_retract(:),
76 scasp_retractall(:),
77 scasp_abolish(:),
78 pred(:),
79 show(:),
80 abducible(:). 81
95
122
123scasp(Query, Options) :-
124 Query = SrcModule:_,
125 scasp_query_clauses(Query, Clauses0),
126 expand_program(SrcModule, Clauses0, Clauses1, Query, Query1),
127 maplist(qualify, Clauses1, Clauses2),
128 qualify_query(Query1, SrcModule:QQuery),
129 q_expand_program(SrcModule, Clauses2, Clauses, QQuery, QQuery1),
130 in_temporary_module(
131 Module,
132 prepare(Clauses, Module, Options),
133 scasp_call_and_results(Module:QQuery1, SrcModule, Options)).
134
135prepare(Clauses, Module, Options) :-
136 scasp_compile(Module:Clauses, Options),
137 ( option(write_program(_), Options)
138 -> scasp_portray_program(Module:Options)
139 ; true
140 ).
141
142qualify_query(M:Q0, M:Q) :-
143 qualify(Q0, M, Q1),
144 intern_negation(Q1, Q).
145
146expand_program(SrcModule, Clauses, Clauses1, QQuery, QQuery1) :-
147 current_predicate(SrcModule:scasp_expand/4),
148 SrcModule:scasp_expand(Clauses, Clauses1, QQuery, QQuery1),
149 !.
150expand_program(_, Clauses, Clauses, QQuery, QQuery).
151
152q_expand_program(SrcModule, Clauses, Clauses1, QQuery, QQuery1) :-
153 current_predicate(SrcModule:scasp_expand_program/4),
154 SrcModule:scasp_expand_program(Clauses, Clauses1, QQuery, QQuery1),
155 !.
156q_expand_program(_, Clauses, Clauses, QQuery, QQuery).
157
158
159scasp_call_and_results(Query, SrcModule, Options) :-
160 scasp_embed:scasp_call(Query),
161 ( option(model(Model), Options)
162 -> scasp_model(SrcModule:Model)
163 ; true
164 ),
165 ( option(tree(Tree), Options)
166 -> scasp_justification(SrcModule:Tree, Options)
167 ; true
168 ).
169
181
182scasp_show(Query, What) :-
183 What =.. [Type|Options],
184 scasp_show(Query, Type, Options).
185
186scasp_show(Query, code, Options) =>
187 Query = SrcModule:_,
188 scasp_query_clauses(Query, Clauses0),
189 expand_program(SrcModule, Clauses0, Clauses1, Query, Query1),
190 maplist(qualify, Clauses1, Clauses2),
191 qualify_query(Query1, SrcModule:QQuery),
192 q_expand_program(SrcModule, Clauses2, Clauses, QQuery, _QQuery1),
193 in_temporary_module(
194 Module,
195 prepare(Clauses, Module, []),
196 scasp_portray_program(Module:[source_module(SrcModule)|Options])).
197
201
202:- det(scasp_query_clauses/2). 203
204scasp_query_clauses(Query, Clauses) :-
205 query_callees(Query, Callees0),
206 include_global_constraint(Callees0, Constraints, Callees),
207 findall(Clause, scasp_clause(Callees, Clause), Clauses, Constraints).
208
209scasp_clause(Callees, source(ClauseRef, M:(Head:- Body))) :-
210 member(PI, Callees),
211 pi_head(PI, M:Head),
212 @(clause(Head, Body, ClauseRef), M).
213
214qualify(source(Ref, Clause), Q) =>
215 Q = source(Ref, QClause),
216 qualify(Clause, QClause).
217qualify(M:(Head :- true), Q) =>
218 qualify(Head, M, Q).
219qualify(M:(Head :- Body), Q) =>
220 qualify((Head:-Body), M, Q).
221qualify(M:(:- Body), Q) =>
222 Q = (:- Constraint),
223 qualify(Body, M, Constraint).
224
225qualify(-(Head), M, Q) =>
226 Q = -QHead,
227 qualify(Head, M, QHead).
228qualify(not(Head), M, Q) =>
229 Q = not(QHead),
230 qualify(Head, M, QHead).
231qualify(findall(Templ, Head, List), M, Q) =>
232 Q = findall(Templ, QHead, List),
233 qualify(Head, M, QHead).
234qualify((A,B), M, Q) =>
235 Q = (QA,QB),
236 qualify(A, M, QA),
237 qualify(B, M, QB).
238qualify((A:-B), M, Q) =>
239 Q = (QA:-QB),
240 qualify(A, M, QA),
241 qualify(B, M, QB).
242qualify(G, M, Q), callable(G) =>
243 ( built_in(G)
244 -> Q = G
245 ; implementation(M:G, Callee),
246 encoded_module_term(Callee, Q)
247 ).
248
255
256query_callees(M:Query, Callees) :-
257 findall(Call, body_calls_pi(Query,M,Call), Calls0),
258 sort(Calls0, Calls),
259 callee_graph(Calls, Callees).
260
261body_calls_pi(Query, M, PI) :-
262 body_calls(Query, M, Call),
263 pi_head(PI, Call).
264
265callee_graph(Preds, Nodes) :-
266 empty_assoc(Expanded),
267 callee_closure(Preds, Expanded, Preds, Nodes0),
268 sort(Nodes0, Nodes).
269
270callee_closure([], _, Preds, Preds).
271callee_closure([H|T], Expanded, Preds0, Preds) :-
272 ( get_assoc(H, Expanded, _)
273 -> callee_closure(T, Expanded, Preds0, Preds)
274 ; put_assoc(H, Expanded, true, Expanded1),
275 pi_head(H, Head),
276 predicate_callees(Head, Called),
277 exclude(expanded(Expanded1), Called, New),
278 append(New, T, Agenda),
279 append(New, Preds0, Preds1),
280 callee_closure(Agenda, Expanded1, Preds1, Preds)
281 ).
282
283expanded(Assoc, PI) :-
284 get_assoc(PI, Assoc, _).
285
287
288include_global_constraint(Callees0, Constraints, Callees) :-
289 include_global_constraint(Callees0, Callees, [], Constraints).
290
291include_global_constraint(Callees0, Callees, Constraints0, Constraints) :-
292 global_constraint(Constraint),
293 Constraint = source(_, Rule), 294 \+ ( member(source(_, Rule0), Constraints0),
295 Rule =@= Rule0
296 ),
297 Rule = M:(:-Body),
298 query_callees(M:Body, Called),
299 ord_intersect(Callees0, Called),
300 !,
301 ord_union(Callees0, Called, Callees1),
302 include_global_constraint(Callees1, Callees,
303 [Constraint|Constraints0], Constraints).
304include_global_constraint(Callees, Callees, Constraints, Constraints).
305
306
307global_constraint(source(Ref, M:(:- Body))) :-
308 ( current_temporary_module(M)
309 ; current_module(M)
310 ),
311 current_predicate(M:(-)/0),
312 \+ predicate_property(M:(-), imported_from(_)),
313 @(clause(-, Body, Ref), M).
314
319
320:- dynamic predicate_callees_c/4. 321
322predicate_callees(M:Head, Callees) :-
323 predicate_callees_c(Head, M, Gen, Callees0),
324 predicate_generation(M:Head, Gen),
325 !,
326 Callees = Callees0.
327predicate_callees(M:Head, Callees) :-
328 module_property(M, class(temporary)),
329 !,
330 predicate_callees_nc(M:Head, Callees).
331predicate_callees(M:Head, Callees) :-
332 retractall(predicate_callees_c(Head, M, _, _)),
333 predicate_callees_nc(M:Head, Callees0),
334 predicate_generation(M:Head, Gen),
335 assertz(predicate_callees_c(Head, M, Gen, Callees0)),
336 Callees = Callees0.
337
338predicate_callees_nc(Head, Callees) :-
339 findall(Callee, predicate_calls(Head, Callee), Callees0),
340 sort(Callees0, Callees).
341
342predicate_calls(Head0, PI) :-
343 generalise(Head0, M:Head),
344 @(clause(Head, Body), M),
345 body_calls(Body, M, Callee),
346 pi_head(PI, Callee).
347
348body_calls(Goal, _M, _), var(Goal) =>
349 instantiation_error(Goal).
350body_calls(true, _M, _) => fail.
351body_calls((A,B), M, Callee) =>
352 ( body_calls(A, M, Callee)
353 ; body_calls(B, M, Callee)
354 ).
355body_calls(not(A), M, Callee) =>
356 body_calls(A, M, Callee).
357body_calls(findall(_,G,_), M, Callee) =>
358 body_calls(G, M, Callee).
359body_calls(N, M, Callee), rm_classic_negation(N,A) =>
360 body_calls(A, M, Callee).
361body_calls(M:A, _, Callee), atom(M) =>
362 body_calls(A, M, Callee).
363body_calls(G, _M, _CalleePM), callable(G), built_in(G) =>
364 fail.
365body_calls(G, M, CalleePM), callable(G) =>
366 implementation(M:G, Callee0),
367 generalise(Callee0, Callee),
368 ( predicate_property(Callee, interpreted),
369 \+ predicate_property(Callee, meta_predicate(_))
370 -> pm(Callee, CalleePM)
371 ; \+ predicate_property(Callee, _)
372 -> pm(Callee, CalleePM) 373 ; pi_head(CalleePI, Callee),
374 permission_error(scasp, procedure, CalleePI)
375 ).
376body_calls(G, _, _) =>
377 type_error(callable, G).
378
379built_in(Head) :-
380 prolog_builtin(Head).
381built_in(Head) :-
382 clp_builtin(Head).
383built_in(Head) :-
384 clp_interval(Head).
385built_in(_ is _).
386built_in(findall(_,_,_)).
387
388rm_classic_negation(-Goal, Goal) :-
389 !.
390rm_classic_negation(Goal, PGoal) :-
391 functor(Goal, Name, _),
392 atom_concat(-, Plain, Name),
393 Goal =.. [Name|Args],
394 PGoal =.. [Plain|Args].
395
396pm(P, P).
397pm(M:P, M:MP) :-
398 intern_negation(-P, MP).
399
400implementation(M0:Head, M:Head) :-
401 predicate_property(M0:Head, imported_from(M1)),
402 !,
403 M = M1.
404implementation(Head, Head).
405
406generalise(M:Head0, Gen), atom(M) =>
407 Gen = M:Head,
408 generalise(Head0, Head).
409generalise(-Head0, Gen) =>
410 Gen = -Head,
411 generalise(Head0, Head).
412generalise(Head0, Head) =>
413 functor(Head0, Name, Arity),
414 functor(Head, Name, Arity).
415
416predicate_generation(Head, Gen) :-
417 predicate_property(Head, last_modified_generation(Gen0)),
418 !,
419 Gen = Gen0.
420predicate_generation(_, 0).
421
422
423 426
433
434scasp_dynamic(M:Spec) :-
435 scasp_dynamic(Spec, M, private).
436scasp_dynamic(M:(Spec as Scoped)) :-
437 scasp_dynamic(Spec, M, Scoped).
438
439scasp_dynamic((A,B), M, Scoped) =>
440 scasp_dynamic(A, M, Scoped),
441 scasp_dynamic(B, M, Scoped).
442scasp_dynamic(Name/Arity, M, Scoped) =>
443 atom_concat(-, Name, NName),
444 ( Scoped == shared
445 -> dynamic((M:Name/Arity,
446 M:NName/Arity))
447 ; thread_local((M:Name/Arity,
448 M:NName/Arity))
449 ).
450
451:- multifile system:term_expansion/2. 452
453system:term_expansion((:- scasp_dynamic(Spec)), Directives) :-
454 phrase(scasp_dynamic_direcives(Spec), Directives).
455
456scasp_dynamic_direcives(Spec as Scope) -->
457 !,
458 scasp_dynamic_direcives(Spec, Scope).
459scasp_dynamic_direcives(Spec) -->
460 !,
461 scasp_dynamic_direcives(Spec, private).
462
463scasp_dynamic_direcives(Var, _) -->
464 { var(Var), !, fail }.
465scasp_dynamic_direcives((A,B), Scope) -->
466 scasp_dynamic_direcives(A, Scope),
467 scasp_dynamic_direcives(B, Scope).
468scasp_dynamic_direcives(Name/Arity, Scope) -->
469 { atom_concat(-, Name, NName) },
470 ( {Scope == shared}
471 -> [(:- dynamic((Name/Arity, NName/Arity)))]
472 ; [(:- thread_local((Name/Arity, NName/Arity)))]
473 ).
474
475
487
488scasp_assert(Clause) :-
489 scasp_assert(Clause, false).
490
491scasp_assert(M:(-Head :- Body0), Pos) =>
492 intern_negation(-Head, MHead),
493 expand_goal(Body0, Body),
494 scasp_assert_(M:(MHead :- Body), Pos).
495scasp_assert(M:(-Head), Pos) =>
496 intern_negation(-Head, MHead),
497 scasp_assert_(M:(MHead), Pos).
498scasp_assert(M:(:- Body0), Pos) =>
499 expand_goal(Body0, Body),
500 scasp_assert_(M:((-) :- Body), Pos).
501scasp_assert(M:(false :- Body0), Pos) =>
502 expand_goal(Body0, Body),
503 scasp_assert_(M:((-) :- Body), Pos).
504scasp_assert(M:(Head :- Body0), Pos) =>
505 expand_goal(Body0, Body),
506 scasp_assert_(M:(Head :- Body), Pos).
507scasp_assert(Head, Pos) =>
508 scasp_assert_(Head, Pos).
509
510scasp_assert_(Clause, false) =>
511 assertz(Clause).
512scasp_assert_(Clause, Pos) =>
513 assertz(Clause, Ref),
514 assertz(scasp_dynamic_clause_position(Ref, Pos)).
515
516scasp_assert_into(M, Pos, Rule) :-
517 scasp_assert(M:Rule, Pos).
518
519scasp_retract(M:(-Head :- Body0)) =>
520 intern_negation(-Head, MHead),
521 expand_goal(Body0, Body),
522 retract(M:(MHead :- Body)).
523scasp_retract(M:(-Head)) =>
524 intern_negation(-Head, MHead),
525 retract(M:(MHead)).
526scasp_retract(M:(:- Body0)) =>
527 expand_goal(Body0, Body),
528 retract(M:((-) :- Body)).
529scasp_retract(M:(false :- Body0)) =>
530 expand_goal(Body0, Body),
531 retract(M:((-) :- Body)).
532scasp_retract(M:(Head :- Body0)) =>
533 expand_goal(Body0, Body),
534 retract(M:(Head :- Body)).
535scasp_retract(Head) =>
536 retract(Head).
537
538scasp_retractall(M:(-Head)) =>
539 intern_negation(-Head, MHead),
540 retractall(M:MHead).
541scasp_retractall(Head) =>
542 retractall(Head).
543
548
549scasp_abolish(M:(Name/Arity)) =>
550 pi_head(Name/Arity, Head),
551 scasp_retractall(M:Head),
552 scasp_retractall(M:(-Head)).
553
554
555 558
563
564#(Directive) :- #(Directive, false).
565
566#(M:pred(Spec), _) => pred(M:Spec).
567#(M:show(Spec), _) => show(M:Spec).
568#(M:abducible(Spec), Pos) => abducible(M:Spec, Pos).
569
570pred(M:(Spec :: Template)) =>
571 process_pr_pred(Spec :: Template, Atom, Children, Cond, Human),
572 assertz(M:pr_pred_predicate(Atom, Children, Cond, Human)).
573
574show(M:PIs) =>
575 phrase(show(PIs), Clauses),
576 maplist(assert_show(M), Clauses).
577
578assert_show(M, Clause) :-
579 assertz(M:Clause).
580
581show(Var) -->
582 { var(Var),
583 instantiation_error(Var)
584 }.
585show((A,B)) -->
586 !,
587 show(A),
588 show(B).
589show(not(PI)) -->
590 { pi_head(PI, Head) },
591 [ pr_show_predicate(not(Head)) ].
592show(PI) -->
593 { pi_head(PI, Head) },
594 [ pr_show_predicate(Head) ].
595
600
601abducible(Spec) :- abducible(Spec, false).
602
603abducible(M:(A,B), Pos) =>
604 abducible(M:A, Pos),
605 abducible(M:B, Pos).
606abducible(M:Head, Pos), callable(Head) =>
607 abducible_rules(Head, Rules),
608 maplist(scasp_assert_into(M, Pos), Rules).
609
610abducible_rules(Head,
611 [ (Head :- AHead1),
612 (NegHead :- AHead2),
613 (AHead1 :- not AHead2),
614 (AHead2 :- not AHead1)
615 ]) :-
616 abducible_head('abducible$', Head, AHead1),
617 abducible_head('abducible$$', Head, AHead2),
618 intern_negation(-Head, NegHead).
619
620abducible_head(Prefix, Head, AHead) :-
621 format(atom(AHead), '~w~k$', [Prefix, Head]).
622
623abducible(Var) -->
624 { var(Var),
625 instantiation_error(Var)
626 }.
627abducible((A,B)) -->
628 !,
629 abducible(A),
630 abducible(B).
631abducible(Head) -->
632 { must_be(callable, Head),
633 abducible_rules(Head, Clauses)
634 },
635 list(Clauses).
636
637list([]) --> [].
638list([H|T]) --> [H], list(T).
639
640
641
642 645
646user:term_expansion(-Fact, MFact) :-
647 callable(Fact),
648 Fact \= _:_,
649 intern_negation(-Fact, MFact).
650user:term_expansion((-Head :- Body), (MHead :- Body)) :-
651 callable(Head),
652 Head \= _:_,
653 intern_negation(-Head, MHead).
654user:term_expansion((false :- Body), ((-) :- Body)).
655user:term_expansion((:- pred(SpecIn)),
656 pr_pred_predicate(Atom, Children, Cond, Human)) :-
657 process_pr_pred(SpecIn, Atom, Children, Cond, Human).
658user:term_expansion((:- show(SpecIn)), Clauses) :-
659 phrase(show(SpecIn), Clauses).
660user:term_expansion((:- abducible(SpecIn)), Clauses) :-
661 phrase(abducible(SpecIn), Clauses).
662user:term_expansion((# pred(SpecIn)),
663 pr_pred_predicate(Atom, Children, Cond, Human)) :-
664 process_pr_pred(SpecIn, Atom, Children, Cond, Human).
665user:term_expansion((# show(SpecIn)), Clauses) :-
666 phrase(show(SpecIn), Clauses).
667user:term_expansion((# abducible(SpecIn)), Clauses) :-
668 phrase(abducible(SpecIn), Clauses).
669
670user:goal_expansion(-Goal, MGoal) :-
671 callable(Goal),
672 intern_negation(-Goal, MGoal).
673
674
675 678
688
689A #= B :- apply_clpq_constraints(A #= B).
690A #<> B :- apply_clpq_constraints(A #<> B).
691A #< B :- apply_clpq_constraints(A #< B).
692A #> B :- apply_clpq_constraints(A #> B).
693A #=< B :- apply_clpq_constraints(A #=< B).
694A #>= B :- apply_clpq_constraints(A #>= B).
695
696
697 700
701:- multifile
702 prolog_clause:unify_goal/5. 703
704prolog_clause:unify_goal(scasp(RGoal, Options),
705 scasp(CGoal, Options),
706 _Module,
707 TermPos, TermPos) :-
708 intern_negation(RGoal, RGoal2),
709 RGoal2 =@= CGoal.
710
711
712 715
716:- multifile
717 sandbox:safe_meta_predicate/1. 718
723
724sandbox:safe_meta(scasp_dyncall:scasp(_, _), [])