# Is there a meta\_predicate tutorial?

**URL:** <https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985>\
**Category:** Predicate\
**Created:** [September 30, 2020, 10:51am UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985 "2020-09-30T10:51:55Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [September 30, 2020, 10:51am UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/1 "2020-09-30T10:51:55Z")

</div>

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](https://www.swi-prolog.org/pldoc/man?predicate=meta_predicate/1)  
> SWI-Prolog Predicate @/2  
> SWI-Prolog Section 6.5 [Defining a meta-predicate](https://www.swi-prolog.org/pldoc/man?section=metapred)  
> SWI-Prolog Section 2.12 Environment Control (Prolog flags) - [colon\_sets\_calling\_context/2](https://www.swi-prolog.org/pldoc/man?section=flags#flag:colon_sets_calling_context)  
> SWI-Prolog Section 4.25 [Operators](https://www.swi-prolog.org/pldoc/man?section=operators) - Seems operators were left out when meta\_predicate/1 was designed.
> 
> - SWI-Prolog source code implementation in C
> 
> [pl-proc.c](https://github.com/SWI-Prolog/swipl-devel/blob/8ec11f3093de005244b8e225521d3f9498e1129e/src/pl-proc.c#L1800-L2051)  
> [pl-incl.h](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L1830-L1844)
> 
> - Other Prolog Documentation
> 
> LogTalk [meta\_predicate/1](https://logtalk.org/manuals/refman/directives/meta_predicate_1.html)  
> [Quintus Prolog User’s Manual](https://quintus.sics.se/isl/quintus/pdf/quintus.pdf) - Section 8.13.17 The meta\_predicate Declaration
> 
> SICStus Prolog manual - [Section 5.5 Module Name Expansion](https://sicstus.sics.se/sicstus/docs/3.12.9/html/sicstus/Meta-Exp.html#Meta-Exp)
> 
> > 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](http://swi-prolog.996271.n3.nabble.com/DCG-meta-predicate-error-td14532.html)  
> SWI-Prolog Discourse topic: [Mode declarations vs meta\_predicate/1](https://swi-prolog.discourse.group/t/mode-declarations-vs-meta-predicate-1/1207)  
> SWI-Prolog Discourse topic: [Context module and module prefix attached to arguments [Q]](https://swi-prolog.discourse.group/t/context-module-and-module-prefix-attached-to-arguments-q/322)  
> SWI-Prolog Discourse topic: [How to get multifile to work with dynamic predicates](https://swi-prolog.discourse.group/t/how-to-get-multifile-to-work-with-dynamic-predicates/2889)  
> SWI-Prolog Discourse topic: [Modules design for multi-agent modeling](https://swi-prolog.discourse.group/t/modules-design-for-multi-agent-modeling/557)  
> SWI-Prolog Discourse topic: [How can the module for a term be identified?](https://swi-prolog.discourse.group/t/how-can-the-module-for-a-term-be-identified/1536)  
> SWI-Prolog Discourse topic: [Module finding calling program DCG predicates](https://swi-prolog.discourse.group/t/module-finding-calling-program-dcg-predicates/963)
> 
> StackOverflow - [Custom DCG Operators](https://stackoverflow.com/questions/51562887/custom-dcg-operators)  
> StackOverflow - [Definition of a path/trail/walk](https://stackoverflow.com/questions/30328433/definition-of-a-path-trail-walk)  
> StackOverflow - [Definition of Reflexive Transitive Closure](https://stackoverflow.com/questions/26946133/definition-of-reflexive-transitive-closure)  
> StackOverflow - [How do I code rec/3 in the presence of a meta\_predicate declaration?](https://stackoverflow.com/a/24419952/1243762)  
> StackOverflow - [What kind of meta argument is the first argument of predicate\_property/2?](https://stackoverflow.com/questions/24411920/what-kind-of-meta-argument-is-the-first-argument-of-predicate-property-2)
> 
> - Slides
> 
> [Using Modules](https://folk.idi.ntnu.no/alfw/SWI/node89.html) - These have nice definitions and examples of words like _Context Module_  
> [Name-based versus Predicate-based Modules](https://folk.idi.ntnu.no/alfw/SWI/node91.html#SECTION00420000000000000000)  
> [Meta-Predicates in Modules](https://folk.idi.ntnu.no/alfw/SWI/node97.html#SECTION00460000000000000000)
> 
> [Modules in SWI Prolog](https://sewiki.iai.uni-bonn.de/_media/teaching/lectures/alp/2010/slides/06-modules.pdf) - 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](https://www.swi-prolog.org/pack/file_details/plrand/prolog/prob/strand.pl?show=src)  
> GitHub - [mndrix/dcg\_util.pl](https://gist.github.com/mndrix/572871177fa477e79ddb)
> 
> - Papers
> 
> [SWI-Prolog](https://arxiv.org/pdf/1011.5332.pdf) Section 7.2.1 Meta-predicate handling  
> [A New Module System for Prolog](https://core.ac.uk/download/pdf/148663021.pdf)  
> [Functions in Full Prolog](http://ac.inf.elte.hu/Vol_017_1998/017.pdf)  
> An Elementary Prolog Library Section 2.2 [meta\_predicate](https://www.euroforth.org/ulrich/iso-prolog/pllib-2010-11-19.htm) - This starts to talk about the history of meta\_predicate.  
> Section 4.0 [Compatibility of the Module System](http://www.bowdoin.edu/~allen/courses/cs250/Manual/sec-4.9.html)  
> [Global Analysis of Standard Prolog Programs](https://cliplab.org/papers/full-prolog-esop96.pdf)  
> [Implementing a Module System for SICStus Prolog](http://www.diva-portal.org/smash/get/diva2:1041692/FULLTEXT01.pdf) - Has a few nice images.  
> [Meta-Predicate Semantics](https://www.dcc.fc.up.pt/~ricroc/homepage/publications/leap/2011-LOPSTR-PP.pdf)
> 
> [Towards a Study of Meta-Predicate Semantics](https://arxiv.org/pdf/1009.3773.pdf)
> 
> > 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)](https://webstore.ansi.org/RecordDetail.aspx?sku=INCITS/ISO/IEC%2013211-2-2000%20%28R2006%29) due to [INCITS](https://en.wikipedia.org/wiki/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](https://github.com/Anniepoo/swiplwebtut/blob/master/web.adoc#52-inclusion-and-modules))
> 
> [Anyone using The Prolog Development Tool - A Prolog IDE for Eclipse?](https://swi-prolog.discourse.group/t/anyone-using-the-prolog-development-tool-a-prolog-ide-for-eclipse/3011)  
> [prolog\_xref](https://github.com/SWI-Prolog/swipl-devel/blob/master/library/prolog_xref.pl) has predicate meta\_xref/2,3 ([ref](https://github.com/SWI-Prolog/swipl-devel/blob/master/library/prolog_xref.pl#L1160-L1131)).
> 
> If the code uses [library(option)](https://www.swi-prolog.org/pldoc/man?section=option) and there are `options that are module-sensitive`, then use meta\_options/3 ([ref](https://swi-prolog.discourse.group/t/how-can-the-module-for-a-term-be-identified/1536/22))
> 
> meta\_predicate/1 works with more than just predicates, e.g. operators ([ref](https://github.com/SWI-Prolog/swipl-devel/blob/master/boot/init.pl#L328-L355)) 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](https://swi-prolog.discourse.group/t/how-can-the-module-for-a-term-be-identified/1536/19)), e.g.
> 
> ```prolog
> :- meta_predicate foo(:).
> foo(M:Goal) :-
> true,
> Goal,
> true.
> 
> ```
> 
> Is `//` the same as 2 ([ref](https://github.com/wouterbeek/prolog_library_collection/blob/master/prolog/dcg.pl#L69-L90)), e.g.
> 
> ```prolog
> 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](https://en.wikipedia.org/wiki/Message_passing)  
> [PROGRAMMING WORD OF THE DAY](https://programmingwords.com/)  
> [wiki.c2.com](https://wiki.c2.com/?MessagePassing)
> 
> [Unexpected predicate\_property/2 size changing without editing predicate](https://swi-prolog.discourse.group/t/unexpected-predicate-property-2-size-changing-without-editing-predicate/3014) 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](https://swi-prolog.discourse.group/t/swi-prolog-documentation-mentions-closures-but-these-are-not-the-closures-you-are-looking-for/1840)
> 
> [pl-wrap.h](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-wrap.h#L40-L48)
> 
> ```c
> 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/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](https://www.swi-prolog.org/download/publications/A_Portable_Prolog_Compiler.pdf))
> 
> [I\_CONTEXT](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L1648-L1650)
> 
> > 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.
> 
> [I\_LCALL](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L2252-L2261)
> 
> > 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.
> 
> [S\_MQUAL](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L3386-L3391)
> 
> > 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L5064-L5065)
> 
> > I\_CALLATM: procedure-module, context-module, procedure The procedure-module is provided to support the decompiler.
> 
> [I\_CALLATMV](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L5101-L5102)
> 
> > This instruction deals with @(Callable, Module), where Module is a variable. The module argument can be NULL.
> 
> [I\_CALLM](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L5133-L5135)
> 
> > 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L5147-L5156)
> 
> > 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-vmi.c#L5312)
> 
> > I\_USERCALLN: translation of call(Goal, Arg1, …)
> 
> ```c
> typedef struct module * Module; /* predicate modules */
> 
> ```
> 
> ([ref](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L694))
> 
> ```c
> #define P_TRANSPARENT (0x00040000) /* Inherit calling module */
> 
> ```
> 
> ([ref](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L869))
> 
> ```c
> #define P_MFCONTEXT (0x00100000) /* Used for Goal@Module */
> 
> ```
> 
> ([ref](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L871))
> 
> ```c
> #define CL_BODY_CONTEXT (0x0080) /* Module context of body is different */
> /* from predicate */
> 
> ```
> 
> ([ref](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L899-L900))
> 
> ```c
> 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L1511-L1525))
> 
> ```c
> 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-incl.h#L1784-L1807))
> 
> ```c
> 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](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-funcs.h))
> 
> Many of the c functions related to using Prolog modules are in [pl-modul.c](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-modul.c)
> 
> CODE GENERATION  
> int [compileClause(Clause \*cp, Word head, Word body, Procedure proc, Module module, term\_t warnings ARG\_LD)](https://github.com/SWI-Prolog/swipl-devel/blob/431bddd1b1ddbbb142969201e3057f04ee1536b2/src/pl-comp.c#L1564-L1824) …
> 
> Context Module  
> Module [contextModule(LocalFrame fr)](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-wam.c#L1468-L1478) …  
> void [setContextModule(LocalFrame fr, Module context)](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-wam.c#L1488-L1492) …
> 
> MA\_NEEDS\_TRANSPARENT [1](https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-supervisor.c#L332-L368)
> 
> FR\_CONTEXT
> 
> O\_CALL\_AT\_MODULE @
> 
> multifile
> 
> strip\_module PL\_strip\_module\_ex  
> lookupModule
> 
> target\_module  
> getTargetModule  
> pushTargetModule
> 
> definition-\>module
> 
> * * *

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [September 30, 2020, 11:53am UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/2 "2020-09-30T11:53:54Z")

</div>

One link that is missing from your list, somehow, is the _section_ on [defining a meta-predicate](https://www.swi-prolog.org/pldoc/man?section=metapred). It gives a pretty good overview it seems.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [September 30, 2020, 12:34pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/3 "2020-09-30T12:34:09Z")

</div>

> [@Boris](#):
>
> One link that is missing from your list, somehow, is the _section_ on [defining a meta-predicate](https://www.swi-prolog.org/pldoc/man?section=metapred).

When I use a reference in the SWI-Prolog documentation I will typically click in the left menu the section name for a specific predicate. Doing so for meta\_predicate/1 is the same as the link you provided.

While that [section](https://www.swi-prolog.org/pldoc/man?section=metapred) is technically correct, can you use it to answer my questions? I could not. ☹

Don’t take that to mean I dislike the documentation, it just lacks enough information for me to feel confident in understanding and using meta\_predicate/1.

I added it to the list. 🙂

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [September 30, 2020, 6:29pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/4 "2020-09-30T18:29:24Z")

</div>

> [@EricGT](#):
>
> can you use it to answer my questions?

Not sure. The questions are not too specific on first sight. They are answered, in a fashion, in the intro there. I would guess that this is the gist of it:

> The [meta\_predicate/1](https://www.swi-prolog.org/pldoc/man?predicate=meta_predicate/1) directive tells the compiler that certain arguments are terms that will be used to look up a predicate and thus need to be wrapped (qualified) with \<_module_\>:\<_term_\>, unless they are already wrapped.

I strongly suspect that I am missing something from your questions; please forgive me for that.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [September 30, 2020, 6:53pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/5 "2020-09-30T18:53:31Z")

</div>

> [@Boris](#):
>
> I strongly suspect that I am missing something from your questions

Or it could be that I am missing something simple.

One of the problems I am having with Prolog is that sometimes a call needs to be made from one predicate in one module to a predicate in another module. From what I am gathering is that if sometimes the call can not be made is because Prolog does not know which module to use for the predicate. The better way to resolve this seems to be using meta\_predicate/1. See: [Using prolog\_walk\_code/1 to identify meta predicate calls?](https://swi-prolog.discourse.group/t/using-prolog-walk-code-1-to-identify-meta-predicate-calls/2977). In that the call is added at the binary level, but if you list out the source using listing/1 you might expect to see the added meta-predicate, but I don’t. The references talk about other ways to deal with the problem but some are clearly seen as being very wrong, i.e. hardcoding the module with the predicate.

Also if you read some of the references there is a big difference between a Goal and closure, still don’t get that one. Also there are more than one way to solve this problem as noted in “The Craft of Prolog” by Richard O’Keefe Section 6.13 Meta-programs and Object-Oriented Programming.

In trying to understand this, it makes one really have to understand the deeper happenings of the code with regards to calls between modules and history of what it has done to Prolog. It seems in the land of Prolog there was happiness, then modules where added and the world or Prolog shattered like broken glass. ☹

I have been purposefully avoiding mentioning my specific problem because I don’t want the discussion to focus on that particular problem and then still leave me with a large gap in my knowledge. Until today I would not have guessed that cut (!/0) and once/1 would be of consideration with these problems.

---

<div class="post-metadata">

**Author:** ![Boris](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/boris/32/7486_2.png) [@Boris](https://swi-prolog.discourse.group/u/Boris)\
**Post date:** [September 30, 2020, 7:13pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/6 "2020-09-30T19:13:34Z")

</div>

> [@EricGT](#):
>
> I have been purposefully avoiding mentioning my specific problem because I don’t want the discussion to focus on that particular problem and then still leave me with a large gap in my knowledge.

I don’t know about that. My understanding so far is that “knowledge” is just the titbits that each of us has gathered along the way and has at their disposal. I am not sure there is a shortcut to knowledge, in the sense that some deep revelation would somehow allow me to be more knowledgeable with less effort.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [September 30, 2020, 7:56pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/7 "2020-09-30T19:56:30Z")

</div>

I guess the [module tutorial](http://chiselapp.com/user/ttmrichter/repository/gng/doc/trunk/output/tutorials/swiplmodtut.html) is probably one of the best places to start.

Roughly though, the problem is not that hard. We have predicates that live in modules, so the full specification of a predicate is module:name/arity (as a predicate _indicator_) or `module:name(arg1, ....)` as a goal. Now the whole module thing is rather pointless if we have to specify each goal or predicate indicator in its full form, so a simple name/arity or name(arg1, …) needs to refer to the proper module. Using normal code in modules this is rather easy: any such reference in a module refers by default to the module it appears in. This can call/refer to either a locally defined predicate or an _imported_ predicate.

So far, so good. If there were no _meta predicates_ this would be the end of the story. But, we have things that (notably) take _closures_ as an argument and are defined in some other module. If we call `maplist(p, List)`, maplist/2 calls `call(p,Element)`, but we want this called in the module _calling_ the maplist goal, **not** the module in which maplist/2 is defined. That is where meta-arguments come in. If an argument is defined as a meta-argument, as the first argument of maplist/2, the caller adds its module to the argument if this is not already there. So, `p` becomes `m:p`, where `m` is the module making the call to maplist/2.

The machinery only distinguishes _meta arguments_ and _normal arguments_. The first are _qualified_, the latter left untouched. Next, meta\_predicate/1 adds some additional machinery to support code analysis. `:` simply means this is a meta argument without being more specific. `0` means the argument is a goal that will be called. `1` means the argument is a term that will be called using `call(Term, Arg)`, etc.

That is (technically) 99% of the story (there are some more meta-predicate indicators and we have multi-file predicates related to modules as we have seen recently).

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [September 30, 2020, 9:30pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/8 "2020-09-30T21:30:04Z")

</div>

My overly simplistic view of modules: a meta-predicate can expect the `:` (and `0`, `1`, etc.) arguments to be of the form `Module:Term` – and if the caller doesn’t specify the module, it’ll get filled in.

EDIT: I originally typed `?` instead of `:`, which is, of course, nonsensical. So, if you read @jan’s reply, bear in mind that he was responding to my incorrect `?`.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 1, 2020, 6:39am UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/9 "2020-10-01T06:39:48Z")

</div>

Mostly. `?` not though. We have the _meta arguments_ (those that do qualify): `:,//,^,0..9` and the _mode_ arguments (those that do not qualify): `*, ?, -, +`. The mode arguments are documentation only: no part of the system does anything with them. The meta arguments are all the same when it comes to runtime, but they do affect code analysis (cross-referencing) and expand\_goal/2, used to do macro rewriting on goals. So, goal expansion applies to e.g., the 2nd argument of findall/3.

Here, `:` merely qualifies, not affecting anything else. That is used if you write a predicate that needs to do _something_ in the module it is called from. `0..9` stands for call/1…10, `//` for DCG expansion (1st arg of phrase/2) and `^` for existential binding as in setof/3.

This was mostly invented by Quintus. I don’t know who introduced `*` (Paulo?). I have added `//` and `^`.

---

<div class="post-metadata">

**Author:** ![torbjorn.lager](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/torbjorn.lager/32/7890_2.png) [@torbjorn.lager](https://swi-prolog.discourse.group/u/torbjorn.lager)\
**Post date:** [October 1, 2020, 11:11am UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/10 "2020-10-01T11:11:14Z")

</div>

For those who want to delve much deeper into the subject of meta predicates, Paulo Moura has written a whole [paper](https://www.dcc.fc.up.pt/~ricroc/homepage/publications/leap/2011-LOPSTR-PP.pdf) about it.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 1, 2020, 5:22pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/11 "2020-10-01T17:22:55Z")

</div>

Oops … I meant `:` and typed `?`.

As to who invented this flavour of modules – I vaguely remember some discussion about it at Quintus around 1991 … I’m pretty sure it’s quite a bit older than 1991 and that Richard O’Keefe was involved, but not sure whose original idea it was. If you wish, I can ask some ex-Quintus people …

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 1, 2020, 5:27pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/12 "2020-10-01T17:27:04Z")

</div>

> [@peter.ludemann](#):
>
> If you wish, I can ask some ex-Quintus people

Thanks, but no.

I really just want my code to work without the hacks and understand why the fix worked. Currently the hacks are duplicating code into other modules.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 1, 2020, 7:19pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/13 "2020-10-01T19:19:47Z")

</div>

> [@EricGT](#):
>
> big difference between a Goal and closure

From a theoretical point of view, there is a big difference, but from a practical point of view, not so much. You can print out closures to understand what’s going on – they’re just terms.

Note that you can put “_module_:” in front of a compound goal, e.g. `some_module:(goal1(X), goal2(X,Y))`.

Maybe your problem is in understanding how use\_module/1 (and similar) modify the namespace in the current module?  
TL;DR: all the imported names get added to the current module’s namespace. E.g., if you import `foo:bar/1` into module `qqsv` (by `:-use_module(foo,[bar/1])`), then `qqsv:bar(X)` is the same as `foo:bar(X)` and if in module `qqsv` you don’t specify the module, `qqsv` is implicitly used – that is, `bar(X)` is the same as `qqsv:bar(X)` and for a call to a meta\_predicate, `qqsv:` will be added if no module is explicitly given (for args specified by `:`, `0`, etc.).

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [October 2, 2020, 5:02pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/14 "2020-10-02T17:02:07Z")

</div>

> [@EricGT](#):
>
> difference between a Goal and closure,

Thanks for the [response](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/13) Peter.

* * *

In further searching found

[Towards a Study of Meta-Predicate Semantics](https://arxiv.org/pdf/1009.3773.pdf) by Paulo Moura

for which footnote 1 reads

> In Prolog and Logtalk, a closure is defined as a callable term used to construct a  
> goal by appending one or more additional arguments.

So for now will take that to mean that _Goals_ can not use a number for the meta argument specifier but that _Closures_ will require a number for the meta argument specifier.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 2, 2020, 9:28pm UTC](https://swi-prolog.discourse.group/t/is-there-a-meta-predicate-tutorial/2985/15 "2020-10-02T21:28:04Z")

</div>

> [@EricGT](#):
>
> So for now will take that to mean that _Goals_ can not use a number for the meta argument specifier but that _Closures_ will require a number for the meta argument specifier.

First off, I don’t think that the concept of “closure” is very meaningful in Prolog. In the cases of languages like Python or Lisp, a closure can capture “hidden” local variables; in Prolog, everything is visible and captured in the term. (Python also has tricky semantics of one of the local variables in the closure is a global value that is modified; this isn’t a problem in Prolog because it doesn’t have mutable variables.)

A meta-predicate specifier of `0` merely means that the goal is used as-is, and isn’t called with additional arguments. For example (note that `0` is used in the `meta_predicate` declaration but `:` in the [mode comment](https://www.swi-prolog.org/pldoc/man?section=modes):

```prolog
:- meta_predicate must_once(0).

%! must_once(:Goal) is det.
must_once(Goal) :-
    ( call(Goal)
    -> true
    ; throw(error(must_once_failed(Goal), _))
    ).

```

However, it’s probably most common to append arguments, such as in maplist/2 (the library definition is a bit more complex, for efficiency):

```prolog
:- meta_predicate maplist(1, ?).

%! maplist(:Pred, ?List) is det.
maplist(_Pred, []).
maplist(Pred, [Elem|Tail]) :-
    call(Pred, Elem),
    maplist(Pred, Tail).

```

And it could be used like this: `maplist(positive_integer, [1,2,3,4])` or `maplist(must_be(between(0,10)), [1,2,3,4])`.

As @jan mentioned, `0`, `1`, etc. in meta-predicate declarations are treated like `:` when there’s a call; they’re used by things like list\_undefined/0, to check for calls that appear in meta-predicates.
