11.3.97 goal_expansion/5   hook


M:goal_expansion(+Goal1, +Layout1, +Module, -Goal2, -Layout2)

Defines transformations on goals while clauses are being compiled or asserted, and during meta-calls at runtime.




Goal to transform.



Layout of goal to transform.



Source module of goal to transform.



Transformed goal.



Layout of transformed goal.


Defines transformations on goals while clauses are being consulted, compiled or asserted, after any processing by user:term_expansion/6 of the terms being read in. It is called for every simple Goal1, defined in M, in the source module Module found while traversing the clause bodies. Typically, Module has imported the predicate Goal1 from module M but it happens also if Module uses an explicit module prefix, i.e. M:Goal1.

If it succeeds, Goal1 is replaced by Goal2; otherwise, Goal1 = Goal2. Goal2 may be an arbitrarily complex goal, and M:goal_expansion/5 is recursively applied to the expansion and its subgoals.

Please note: the arguments of meta-predicates such as call/1, setof/3 and on_exception/3 are not subject to such compile-time processing. Instead the expansion is performed at runtime, see below.

The above description holds even if Goal1 is exported but not defined in the module M, i.e. it is possible to define a goal expansion for an exported, but otherwise undefined, predicate. However, in general, it is better to provide an ordinary predicate definition as a fallback, e.g. to be able to handle meta calls if the goal expansion is not defined at runtime.

This predicate is also used to resolve any meta-calls to Goal1 at runtime via the same mechanism. If the transformation succeeds, Goal2 is simply called instead of Goal1. Otherwise, if Goal1 is a goal of an existing predicate, that predicate is invoked. Otherwise, error recovery is attempted by user:unknown_predicate_handler/3.

M:goal_expansion/5 can be regarded as a macro expansion facility. It is used for this purpose to support the interface to attributed variables in library(atts), which defines the predicates M:get_atts/2 and M:put_atts/2 to access module-specific variable attributes. These “predicates” are actually implemented via the M:goal_expansion/5 mechanism. This has the effect that calls to the interface predicates are expanded at compile time to efficient code.

For accessing aspects of the load context, e.g. the name of the file being compiled, the predicate prolog_load_context/2 (see ref-lps-lco) can be used. Note that prolog_load_context/2 only gives meaningful results during compile (or consult) time. This means that when a meta call is goal expanded, at runtime, the load context will not be available, and there is no reliable way for a goal expansion to distinguish between these cases.

The goal expansion may happen both at compile time (the normal case) at runtime (for meta calls). In some cases the compiler may try to avoid meta calls by calling goal expansion also for meta calls. This all means that the code implementing goal expansion should be present at both compile time and runtime. It also implies that goal expansion should not misbehave if it is called more times than expected.

Layout1 and Layout2 are for supporting source-linked debugging in the context of goal expansion. The predicate should construct a suitable Layout2 compatible with Term2 that contains the line number information from Layout1. If source-linked debugging of Term2 is not important, Layout2 should be []. The recording of source info is affected by the source_info prolog flag (see ref-lps-flg).


Exceptions are treated as failures, except an error message is printed as well.

See Also

ref-lod-exp, Glossary.

Send feedback on this subject.