Confused about asserta/2 when clause uses predicates from multiple modules

In adding a hook for prolog_trace_interception/4 by using asserta/2 and then verifying the clause, when the clause uses predicates from different modules the asserted clause is not what I expected.


For example in a module named examples is this asserta/2 in a predicate example_01/1

asserta(
	(
		user:prolog_trace_interception(Port, Frame, Choice, continue) :-
			prolog_debug:debug('egt','@~a',['2a']),
			user:format('Port: ~w, Frame: ~w, Choice: ~w~n',[Port,Frame,Choice])
	),
	Ref
)

right after calling asserta/2 is a call to check_01/1 (see below)

check_01(Module) :-
    (
        current_predicate(prolog_trace_interception/4), !,
        nl,
        listing(Module:prolog_trace_interception)
    ;
        true
    ).

The call to check_01/1 lists the actual clause

:- dynamic prolog_trace_interception/4.

prolog_trace_interception(A, B, C, continue) :-
    examples:
    (   prolog_debug:debug(egt, '@~a', ['2a']),
        user:format('Port: ~w, Frame: ~w, Choice: ~w~n', [A, B, C])
    ).

The clause expected is

:- dynamic prolog_trace_interception/4.

prolog_trace_interception(A, B, C, continue) :-
    prolog_debug:debug(egt, '@~a', ['2a']),
    user:format('Port: ~w, Frame: ~w, Choice: ~w~n', [A, B, C]).

The actual clause works in running code.

I just want to make sure I did nothing wrong or that there is a more correct way to add the dynamic clause. If there is another way, the adding of the clause does not even have to be via assert, it could be via one of the lower level predicates that start with $.


EDIT

After seeing reply by Jan W.

Using

asserta(
	user:
	(
		prolog_trace_interception(Port, Frame, Choice, continue) :-
			debug(egt, '@~a', ['2a']),
			format('Port: ~w, Frame: ~w, Choice: ~w~n',[Port,Frame,Choice])
	),
	Ref
)

the call to check_01/1 now lists the actual clause as

:- dynamic prolog_trace_interception/4.

prolog_trace_interception(A, B, C, continue) :-
    debug(egt, '@~a', ['2a']),
    format('Port: ~w, Frame: ~w, Choice: ~w~n', [A, B, C]).

assert/1 asserts the clause in the current module context. If you merely qualify the head the clause is added to the qualified module, but the body remains in the context of the context module. If you want to assert as if asserted from some module, use

 asserta(TargetModule:(Head :- Body)).
1 Like

Is there any difference between this and

TargetModule:asserta((Head :- Body)).

?

Not when it comes to the module awareness of the target clause. The second form does cause asserta/1 to be imported into TargetModule. The first version uses asserta/1 in the module where it is called. From the Quintus days, Module:Goal calls Goal in Module and qualifies all non-qualified meta-arguments with Module.

1 Like