In short if I were asked to explain why is meta_predicate/1 needed, how does it solve the problem, what are it’s short comings, how does it modify the code, how to show a visual representation of the changes, how can the changes to the source code be seen, etc., I would not be able to answer any of these with certainty.
I have found a few pages that give some clues, and some example code but there is not enough evidence to seal the case.
While I don’t expect to find the perfect tutorial for meta_predicate/1 (prefer it be specific to SWI-Prolog), I am all ears if you know a good tutorial or just references that added to your understanding of meta_predicate/1.
Here are some of my better references
- SWI-Prolog Documentation
SWI-Prolog Predicate meta_predicate/1
SWI-Prolog Predicate @/2
SWI-Prolog Section 6.5 Defining a meta-predicate
SWI-Prolog Section 2.12 Environment Control (Prolog flags) - colon_sets_calling_context/2
SWI-Prolog Section 4.25 Operators - Seems operators were left out when meta_predicate/1 was designed.
- SWI-Prolog source code implementation in C
- Other Prolog Documentation
LogTalk meta_predicate/1
Quintus Prolog User’s Manual - Section 8.13.17 The meta_predicate Declaration
SICStus Prolog manual - Section 5.5 Module Name Expansion
Goals appearing in queries and meta-calls are expanded prior to execution while goals in the bodies of clauses and directives are expanded at compile time.
Need to see if this holds true for SWI-Prolog.
- Forums
Google Groups for SWI-Prolog - DCG meta-predicate error
SWI-Prolog Discourse topic: Mode declarations vs meta_predicate/1
SWI-Prolog Discourse topic: Context module and module prefix attached to arguments [Q]
SWI-Prolog Discourse topic: How to get multifile to work with dynamic predicates
SWI-Prolog Discourse topic: Modules design for multi-agent modeling
SWI-Prolog Discourse topic: How can the module for a term be identified?
SWI-Prolog Discourse topic: Module finding calling program DCG predicates
StackOverflow - Custom DCG Operators
StackOverflow - Definition of a path/trail/walk
StackOverflow - Definition of Reflexive Transitive Closure
StackOverflow - How do I code rec/3 in the presence of a meta_predicate declaration?
StackOverflow - What kind of meta argument is the first argument of predicate_property/2?
- Slides
Using Modules - These have nice definitions and examples of words like Context Module
Name-based versus Predicate-based Modules
Meta-Predicates in Modules
Modules in SWI Prolog - This is source code with annotations that give meaning to a picture is worth a thousand words.
- Prolog Source Code using meta_predicate/1
SWI-Prolog pack -strand
GitHub - mndrix/dcg_util.pl
- Papers
SWI-Prolog Section 7.2.1 Meta-predicate handling
A New Module System for Prolog
Functions in Full Prolog
An Elementary Prolog Library Section 2.2 meta_predicate - This starts to talk about the history of meta_predicate.
Section 4.0 Compatibility of the Module System
Global Analysis of Standard Prolog Programs
Implementing a Module System for SICStus Prolog - Has a few nice images.
Meta-Predicate Semantics
Towards a Study of Meta-Predicate Semantics
The :/2 operator both calls a predicate in another module and changes the calling context of the predicate to that module.
The idea of the meta_predicate/1 directive is to avoid the need for explicit qualifications in the first place.
- Books
“The Craft of Prolog” Section 6.13 Meta-programs and Object-Oriented Programming
“The Art of Prolog” Section 10.5 Background - Notes when some the problems first asked.
- Standards
ISO/IEC 13211-2:2000. Part 2: Modules. Published 2000-06-01. Also available much cheaper as INCITS/ISO/IEC 13211-2:2000 (R 2006) due to INCITS.
Personal Notes
After years of trying to understand these this statement by Annie hits the nail on the head.
The fix there is the
meta_predicate/1
declaration, which marks which arguments are module sensitive . (ref)
Anyone using The Prolog Development Tool - A Prolog IDE for Eclipse?
prolog_xref has predicate meta_xref/2,3 (ref).
If the code uses library(option) and there are options that are module-sensitive
, then use meta_options/3 (ref)
meta_predicate/1 works with more than just predicates, e.g. operators (ref) and facts ??? (need ref).
Is it incorrect to add a module variable (e.g. M
) for a meta-predicate since the meta_predicate/1 will set the module based on context_module/1 (ref), e.g.
:- meta_predicate foo(:).
foo(M:Goal) :-
true,
Goal,
true.
Is //
the same as 2 (ref), e.g.
dcg_call(//, ?, ?),
dcg_call(3, ?, ?, ?),
dcg_call(4, ?, ?, ?, ?),
dcg_call(5, ?, ?, ?, ?, ?),
dcg_call(6, ?, ?, ?, ?, ?, ?),
dcg_call(7, ?, ?, ?, ?, ?, ?, ?),
In SWI-Prolog sometimes for meta-predicates the code uses strip_module/3 and sometimes it does not. Is this because the strip_module/3 was used before meta_predicate/1 was created/used here, then when strip_module/3 was deprecated and meta_predicate/1 was used, the way of adding the module to the meta-predicates had to change?
Message Passing:
Wikipedia
PROGRAMMING WORD OF THE DAY
wiki.c2.com
Unexpected predicate_property/2 size changing without editing predicate in this post in the personal notes references SWI-Prolog C source code where the the C level structures are modified when MA_NEEDS_TRANSPARENT
is used.
Related to the definition of closure
SWI Prolog documentation mentions “closures” - but these are not the “closures” you are looking for
typedef struct closure
{ struct definition def;
} closure;
GLOBAL PL_blob_t _PL_closure_blob;
COMMON(void) resetWrappedSupervisor(Definition def);
COMMON(int) get_closure_predicate__LD(term_t t, Definition *def ARG_LD);
#define get_closure_predicate(t, def) get_closure_predicate__LD(t, def PASS_LD)
SWI-Prolog source code implementation in C
Since SWI-Prolog is implemented using Virtual Machine Instructions (VMI) and the instructions are defined in pl-vmi.c this is the lowest level to start the understanding the source code.
A Portable Prolog Compiler by D.L. Bowen, L.H. Byrd and W.F. Clocksin (pdf)
I_CONTEXT is used by non-meta predicates that are compiled into a different module using : :- . The I_CONTEXT instruction immediately follows the I_ENTER. The argument is the module.
Actual tail call. The arguments for the new predicate have been set by now. The number of arguments may be both more and less than for the running frame. As we may need to perform callbacks this is a bit of a problem.
- If we perform the callbacks giving the current GC context we go wrong if the new predicate has more arguments than the current clause has
prolog_vars
. - If we first change the context to the new predicate we can perform the callbacks, but we still need to fix the calling context.
Meta-predicate argument qualification. S_MQUAL qualifies the Nth argument. S_LMQUAL does the same and resets the context module of the frame to be definition module of the predicate, such that unqualified calls refer again to the definition module. This sequence must be processed as part of the supervisor, notably before creating the first choicepoint.
I_CALLATM: procedure-module, context-module, procedure The procedure-module is provided to support the decompiler.
This instruction deals with @(Callable, Module), where Module is a variable. The module argument can be NULL.
I_CALLM deals with qualified calls. The unfortunate task is to sort out the context module for calling a transparent procedure. This job is the same as the end of I_USERCALL.
I_USERCALL0 is generated by the compiler if a variable is encountered as a subclause. Note that the compount statement opened here is encloses also I_CALL. This allows us to use local register variables, but still jump to the `normal_call’ label to do the common part of all these three virtual machine instructions.
I_USERCALL0 has the task of analysing the goal: it should fill the ->procedure slot of the new frame and save the current program counter. It also is responsible of filling the argument part of the environment frame with the arguments of the term.
I_USERCALLN: translation of call(Goal, Arg1, …)
typedef struct module * Module; /* predicate modules */
(ref)
#define P_TRANSPARENT (0x00040000) /* Inherit calling module */
(ref)
#define P_MFCONTEXT (0x00100000) /* Used for Goal@Module */
(ref)
#define CL_BODY_CONTEXT (0x0080) /* Module context of body is different */
/* from predicate */
(ref)
struct localFrame
{ Code programPointer; /* pointer into program */
LocalFrame parent; /* parent local frame */
ClauseRef clause; /* Current clause of frame */
Definition predicate; /* Predicate we are running */
Module context; /* context module of frame */
#ifdef O_PROFILE
struct call_node *prof_node; /* Profiling node */
#endif
#ifdef O_LOGICAL_UPDATE
lgen_t generation; /* generation of the database */
#endif
unsigned int level; /* recursion level */
unsigned int flags; /* packed long holding: */
};
(ref)
struct module
{ atom_t name; /* name of module */
atom_t class; /* class of the module */
SourceFile file; /* file from which module is loaded */
Table procedures; /* predicates associated with module */
Table public; /* public predicates associated */
Table operators; /* local operator declarations */
ListCell supers; /* Import predicates from here */
ListCell lingering; /* Lingering definitions */
size_t code_size; /* #Bytes used for its procedures */
size_t code_limit; /* Limit for code_size */
#ifdef O_PLMT
counting_mutex *mutex; /* Mutex to guard module modifications */
struct thread_wait_area *wait;/* Manage waiting threads */
#endif
#ifdef O_PROLOG_HOOK
Procedure hook; /* Hooked module */
#endif
int level; /* Distance to root (root=0) */
unsigned int line_no; /* Source line-number */
unsigned int flags; /* booleans: */
int references; /* see acquireModule() */
gen_t last_modified; /* Generation I was last modified */
};
(ref)
COMMON(Module) contextModule(LocalFrame fr);
COMMON(void) setContextModule(LocalFrame fr, Module context);
COMMON(Module) lookupModule__LD(atom_t name ARG_LD);
COMMON(Module) isCurrentModule__LD(atom_t name ARG_LD);
COMMON(Module) acquireModule__LD(atom_t name ARG_LD);
COMMON(void) releaseModule(Module m);
COMMON(int) addModuleSourceFile(SourceFile sf, Module m);
COMMON(int) setSuperModule(Module m, Module s);
COMMON(int) setSuperModule(Module m, Module s);
COMMON(int) isSuperModule(Module s, Module m);
COMMON(int) isSuperModule(Module s, Module m);
COMMON(void) clearSupersModule(Module m);
COMMON(int) addSuperModule(Module m, Module s, int where);
COMMON(int) addSuperModule(Module m, Module s, int where);
COMMON(int) getUnknownModule(Module m);
COMMON(Word) stripModule(Word term, Module *module, int flags ARG_LD);
COMMON(bool) isPublicModule(Module module, Procedure proc);
COMMON(int) exportProcedure(Module module, Procedure proc);
COMMON(Module) advanceModuleEnum(ModuleEnum en);
COMMON(int) currentOperator(Module m, atom_t name, int kind,
COMMON(int) priorityOperator(Module m, atom_t atom);
COMMON(int) callProlog(Module module, term_t goal, int flags, term_t *ex);
COMMON(Procedure) lookupProcedure(functor_t f, Module m) WUNUSED;
COMMON(Procedure) isCurrentProcedure__LD(functor_t f, Module m ARG_LD);
COMMON(int) importDefinitionModule(Module m,
COMMON(Procedure) lookupProcedureToDefine(functor_t def, Module m);
COMMON(int) get_functor(term_t descr, functor_t *fdef, Module *m, term_t h, int how);
COMMON(int) overruleImportedProcedure(Procedure proc, Module target);
COMMON(bool) abolishProcedure(Procedure proc, Module module);
COMMON(Procedure) resolveProcedure__LD(functor_t f, Module module ARG_LD);
COMMON(Definition) autoImport(functor_t f, Module m);
COMMON(void) unlinkSourceFileModule(SourceFile sf, Module m);
COMMON(int) exportProcedureSource(SourceFile sf, Module module,
COMMON(void) registerReloadModule(SourceFile sf, Module module);
(ref)
Many of the c functions related to using Prolog modules are in pl-modul.c
CODE GENERATION
int compileClause(Clause *cp, Word head, Word body, Procedure proc, Module module, term_t warnings ARG_LD) …
Context Module
Module contextModule(LocalFrame fr) …
void setContextModule(LocalFrame fr, Module context) …
MA_NEEDS_TRANSPARENT 1
FR_CONTEXT
O_CALL_AT_MODULE @
multifile
strip_module PL_strip_module_ex
lookupModule
target_module
getTargetModule
pushTargetModule
definition->module