Looking at Prolog documentation, predicate signatures are sometimes written as following:
foo(:Bar, +Baz, -Qux, ?Mop)
What are :, +, - and ? for and how do I interpret them? Also, are these the only ones that exist or are there more of them?
Those prefix operators, in this context, represent instantiation modes, i.e. they tell you which arguments should be variables or instantiated when calling the predicate. They also tell you if an argument will be (possibly further) instantiated by the call. They can also be used to tell you that an argument is going to be meta-interpreted in some way by the predicate you're calling. Some of these instantiation modes are standard, other depend on the system. The most usual are:
- - the argument should be unbound (likely output argument)
+ - the argument should be bound (input argument)
? - the argument can be either bound or unbound
# - the argument will not be further instantiated by the call
: - the argument will be meta-interpreted in some way (often ambiguous)
0 - the argument will be interpreted as goal and called as such
N - where N is natural number; the argument will be interpreted as a closure that will be composed with N additional arguments to construct a goal that will be called
Different systems provide other or different instantiation modes. For example, for stating that an argument should be ground when calling a predicate, or for stating that an argument should be a predicate indicator or that will be interpreted as a grammar rule body. You will need to refer to the documentation of the Prolog system you're using for the details.
Mode declarations first appeared in the DECsystem-10 compiler in the end of the 1970s. The DECsystem-10 user's guide of 1978-09 being one of the first descriptions. The motivation is given 1982-11-10:
Such information enables the compiler to generate more compact code
making better use of runtime storage. The saving of runtime
storage in particular can often be very substantial. Mode
declarations also help other people to understand how your
program operates.
DECsystem-10
+ — the argument will always be a NON-variable
- — the argument will always be a variable
? — no restriction
Note that these declarations apply to each goal. Most notably, they apply to recursive goals. In this manner the following mode declaration plus its definition implies that the second argument is not a partial list. Thus, a goal member(A, [c|_]) would be not conforming. So the interface and the implementation are somewhat interdependent which can lead to quite complex cases, when unifications performed by the predicate itself have to be taken into account.
:- mode member(?, +).
member(X, [X|_]). % member(X, [X,.._]) in DEC10
member(X, [_|L]) :-
member(X, L).
In case a mode declaration is violated by a concrete goal, the declaration is either ignored, or will produce an error which at that time meant writing out an error message and failing. The DECsystem-10 interpreter always ignored the declarations.
Deep down in the 1970s, the DEC 10 User's guide thus gave rise of two interpretations to mode declarations: The first being the prescriptive one that does produce errors in case the modes are not met by a caller. The second one being entirely informal, ignoring the mode declarations at runtime. The former is used within the Prolog standard, the latter is found in the documentation of some Prolog systems.
ISO/IEC-Prolog: Template and modes subclause
The Prolog standard (ISO/IEC 13211-1:1995, 2007, 2012) uses the following format for the definition of built-in predicates. It starts with subclause .1 Description, .2 Template and modes, .3 Errors, and optionally continues with .4 Examples, .5 Bootstrapped built-in predicate(s).
8.1.2 Template and modes
A specification for both the type of arguments and which
of them shall be instantiated for the built-in predicate to
be satisfied. The cases form a mutually exclusive set....
The concretes modes are:
+ — the argument shall be instantiated.
# — like + and the argument shall remain unaltered.
- — the argument shall be a variable that will be instantiated iff the goal succeeds.
? — no mode requirement, the argument may be a variable or an instantiated.
If a predicate was called with a differing mode, an instantiation_error or uninstantiation_error is produced. If the type does not match, a type_error is produced.
In this manner the programmer can anticipate many errors simply by looking at the Template and mode subclause without reading the detailed error conditions.
Other systems
Systems that differ from ISO also differ to each other in their precise interpretation of modes. Many perform silent failure in case when a type error would be appropriate. They view mode declarations as a means to indicate cases where the predicate is expected to work with undefined meaning otherwise. Often the - is interpreted roughly as follows. Since there is no actual reference that defines the meaning, this is what I gathered informally:
- — the argument is an "output argument". Meaning that it will be unified with the resulting term after the goal has been executed. So the argument is steadfast. Often, no error is associated with such an argument.
A more modern document is here:
https://www.swi-prolog.org/pldoc/man?section=modes
There are similar annotations for meta-predicates, which should have meta_predicate directives to ensure that they get modules properly added when being called. https://www.swi-prolog.org/pldoc/doc_for?object=(meta_predicate)/1
Related
Some "predicate indicators" (this is the ISO Standard terminology for a syntactic name/arity expression denoting a predicate or functor (both of these terms are equivalent) are not content with a single slash, but actually take two. This always occurs in the context of DCGs. Examples:
syntax_error//1: "Throw the syntax error Error at the current location of the input. This predicate is designed to be called from the handler of phrase_from_file/3."
js_expression(+Expression)//: "Emit a single JSON argument."
According to the recent drafts WDTR 13211-3 (3.19) this is called a non-terminal indicator. Similar to a predicate indicator (3.131) it is used to denote one particular non-terminal.
Note that most implementations translate a non-terminal nt//n to a predicate nt/n+2. You cannot rely on the precise way of translation, though. And thus the outcome of calling a non-terminal directly by calling the corresponding predicate, that is, with the same name and two extra arguments is not defined. In particular the second additional argument has to be handled with care. A direct use might violate steadfastness, in particular when using dcg-semicontext.
What is the meaning of a double slash // after the predicate name in Prolog, appearing in the context of DCGs?
It is used by the term rewrite system of Prolog (SWI-Prolog src), but for a person it lets you know that the predicate is a DCG and has two hidden arguments added to the end of the predicate.
For example here is a very simple DCG that has 1 visible argument.
simple_dcg(X) -->
{ X is 1 + 2 }.
When the listing is seen
?- listing(simple_dcg).
simple_dcg(X, A, B) :-
X is 1+2,
B=A.
true.
the two extra hidden arguments (A, B) appear.
If you have been following my EDCG questions on SWI-Prolog forum then you know it can get much more complicated.
First when I read up on different predicates on Prolog, like for example http_server, it's written like this: http_server(:Goal, +Options) what does : and + mean here? Sometimes ? is also written.
Secondly sometimes I see variables declared with an underscore before them like _Request, even though there isn't any another Request, why is that?
The +, -, : etc. sigils are called mode declarations. They describe the expected instantiation of predicate arguments, i.e., whether you are expected to call the predicate with an unbound variable, an instantiated term, etc. These are not completely standardized; here is a description of the conventions for SWI-Prolog: http://www.swi-prolog.org/pldoc/man?section=modes
As a first approximation, a + argument is an input to the predicate, you are supposed to provide a ground term. A - argument is an output of the predicate, the predicate will try to unify it with a term. A ? term may be partially instantiated at the call, and the predicate may instantiate it further. A : argument is a meta-argument, i.e., it is a goal to be called by the predicate (as in setof/3, for example).
In the example of http_server(:Goal, +Options), you are supposed to call this predicate with the first argument bound to a goal, probably a predicate name. The second argument must be instantiated, presumably to a list whose format is further described in the documentation. If you do not call this predicate like this, for example, if you pass an unbound variable as the second argument, you might get unexpected behavior or an instantiation error.
As for your second question (which would better have been separate), a variable that begins with an underscore is called an anonymous variable. Every such variable may only occur once per clause, except _ itself, which may occur several times and refers to separate variables at each occurrence.
Prolog systems usually emit a "singleton variable" warning for non-anonymous variables that occur only once, because those might be typos or a sign the programmer forgot something. You use anonymous variables to express the notion that "there must be something here (e.g., a predicate argument), but I don't care what it is". In your example, presumably you call a predicate that has a "request" argument, but in your particular use case you don't care about the request.
Looking at Prolog documentation, predicate signatures are sometimes written as following:
foo(:Bar, +Baz, -Qux, ?Mop)
What are :, +, - and ? for and how do I interpret them? Also, are these the only ones that exist or are there more of them?
Those prefix operators, in this context, represent instantiation modes, i.e. they tell you which arguments should be variables or instantiated when calling the predicate. They also tell you if an argument will be (possibly further) instantiated by the call. They can also be used to tell you that an argument is going to be meta-interpreted in some way by the predicate you're calling. Some of these instantiation modes are standard, other depend on the system. The most usual are:
- - the argument should be unbound (likely output argument)
+ - the argument should be bound (input argument)
? - the argument can be either bound or unbound
# - the argument will not be further instantiated by the call
: - the argument will be meta-interpreted in some way (often ambiguous)
0 - the argument will be interpreted as goal and called as such
N - where N is natural number; the argument will be interpreted as a closure that will be composed with N additional arguments to construct a goal that will be called
Different systems provide other or different instantiation modes. For example, for stating that an argument should be ground when calling a predicate, or for stating that an argument should be a predicate indicator or that will be interpreted as a grammar rule body. You will need to refer to the documentation of the Prolog system you're using for the details.
Mode declarations first appeared in the DECsystem-10 compiler in the end of the 1970s. The DECsystem-10 user's guide of 1978-09 being one of the first descriptions. The motivation is given 1982-11-10:
Such information enables the compiler to generate more compact code
making better use of runtime storage. The saving of runtime
storage in particular can often be very substantial. Mode
declarations also help other people to understand how your
program operates.
DECsystem-10
+ — the argument will always be a NON-variable
- — the argument will always be a variable
? — no restriction
Note that these declarations apply to each goal. Most notably, they apply to recursive goals. In this manner the following mode declaration plus its definition implies that the second argument is not a partial list. Thus, a goal member(A, [c|_]) would be not conforming. So the interface and the implementation are somewhat interdependent which can lead to quite complex cases, when unifications performed by the predicate itself have to be taken into account.
:- mode member(?, +).
member(X, [X|_]). % member(X, [X,.._]) in DEC10
member(X, [_|L]) :-
member(X, L).
In case a mode declaration is violated by a concrete goal, the declaration is either ignored, or will produce an error which at that time meant writing out an error message and failing. The DECsystem-10 interpreter always ignored the declarations.
Deep down in the 1970s, the DEC 10 User's guide thus gave rise of two interpretations to mode declarations: The first being the prescriptive one that does produce errors in case the modes are not met by a caller. The second one being entirely informal, ignoring the mode declarations at runtime. The former is used within the Prolog standard, the latter is found in the documentation of some Prolog systems.
ISO/IEC-Prolog: Template and modes subclause
The Prolog standard (ISO/IEC 13211-1:1995, 2007, 2012) uses the following format for the definition of built-in predicates. It starts with subclause .1 Description, .2 Template and modes, .3 Errors, and optionally continues with .4 Examples, .5 Bootstrapped built-in predicate(s).
8.1.2 Template and modes
A specification for both the type of arguments and which
of them shall be instantiated for the built-in predicate to
be satisfied. The cases form a mutually exclusive set....
The concretes modes are:
+ — the argument shall be instantiated.
# — like + and the argument shall remain unaltered.
- — the argument shall be a variable that will be instantiated iff the goal succeeds.
? — no mode requirement, the argument may be a variable or an instantiated.
If a predicate was called with a differing mode, an instantiation_error or uninstantiation_error is produced. If the type does not match, a type_error is produced.
In this manner the programmer can anticipate many errors simply by looking at the Template and mode subclause without reading the detailed error conditions.
Other systems
Systems that differ from ISO also differ to each other in their precise interpretation of modes. Many perform silent failure in case when a type error would be appropriate. They view mode declarations as a means to indicate cases where the predicate is expected to work with undefined meaning otherwise. Often the - is interpreted roughly as follows. Since there is no actual reference that defines the meaning, this is what I gathered informally:
- — the argument is an "output argument". Meaning that it will be unified with the resulting term after the goal has been executed. So the argument is steadfast. Often, no error is associated with such an argument.
A more modern document is here:
https://www.swi-prolog.org/pldoc/man?section=modes
There are similar annotations for meta-predicates, which should have meta_predicate directives to ensure that they get modules properly added when being called. https://www.swi-prolog.org/pldoc/doc_for?object=(meta_predicate)/1
In part one of the ISO standard for Prolog, ISO/IEC 13211-1:1995, the notion of "type" is used to refer to different things. This often leads to confusion.
For example, a page called IsoErrata (archived version, source) states (note that this page is not related to ISO):
7.12.2 and 8.1.2.1
There is a confusion about what a "type" is. There seem to be 3
different groups:
Those that are listed in 8.1.2.1 and also occur as ValidTypes in type_error terms in 7.12.2.b
Those that are listed in 8.1.2.1 and occur as ValidDomain in domain_error terms in 7.12.2.c
Those that are listed in 8.1.2.1 only
In addition, there are ValidDomains in 7.12.2.c that are not listed in
8.1.2.1, presumably by mistake (eg. io_mode).
8.14.3.3.f
The template requires the type atom_or_atom_list for the 3rd argument, but strangely the required error term here is
type_error(list,Operator). This results in (see examples)
op(30,xfy,0) =====> error(type_error(list,0))
where type_error(atom,0) or type_error(atom_or_atom_list,0) would be more appropriate (but note that atom_or_atom_list is not among the
ValidTypes listed in 7.12.2!). For ECLiPSe we have therefore opted for
type_error(list,Op) only if Op is an improper list, and
type_error(atom,Op) if Op is any other non-atom.
So in which meanings is "type" used, and what to do about above confusion?
There are essentially three different uses for "type" in ISO/IEC 13211-1:
Types as defined in 7.1 Types. These are: variable (7.1.1), integer (7.1.2), floating point (7.1.3), atom (7.1.4), compound term (7.1.5) and some types based on them. The next two uses will often refer to 7.1 or to terminology (3 Definitions) for its definition. What is important is that here, variables are included. This classification is motivated by Prolog's syntax:
7.1 Types
The type of any term is determined by its abstract syntax (6.1.2).
Types as defined in 7.12.2 b. These are the types that are used in type errors which are of the form type_error(ValidType, Culprit). Note that variables are now no longer included since these are either signaled as instantiation errors (7.12.2 a) or uninstantiation errors (7.12.2 k, Cor.2).
ValidType ∈ { atom, atomic, byte, callable, character, compound, evaluable, float, in_byte, in_character, integer, list, number, pair, predicate_indicator }
Types as used in the Template and modes subclause:
8.1.2.1 Type of an argument
The type of each argument is defined by one of the following atoms:
atom, atom_or_atom_list, atomic, byte, callable_term, character, character_code, character_code_list, character_list, clause, close_options_list, compound_term, evaluable, flag, head, in_byte, in_character, in_character_code, integer, io_mode, list, nonvar, number, operator_specifier, predicate_indicator, read_options_list, source_sink, stream, stream_options_list, stream_or_alias, stream_position, stream_property, term, write_options_list
Above quote mentioned only 7.12.2 and 8.1.2.1 and how they relate to each other. So this needs some more elaboration:
Types of 7.12.2 are reported with type errors. But types in 8.1.2.1 only serve in the Template and modes subclause of the definition of a built-in. They are not per se suited to be used for errors. In a concrete definition of a built-in predicate, there is a subclause x.y.z.2 Template and modes and x.y.z.3 Errors. Here are some examples of types of 8.1.2.1 (bold in the list above).
write_options_list
There is no direct one-to-one correspondence between write_options_list and the concrete types used in the errors. Instead, a type list and a domain write_option is used. So the complex type write_options_list is never signaled:
8.14.2.2 Template and modes
write_term(#stream_or_alias, #term, #write_options_list)
8.14.2.3 Errors
...
c) Options is neither a partial list nor a list
— type_error(list, Options).
...
e) An element E of the Options list is neither a
variable nor a valid write-option
— domain_error(write_option, E).
atom_or_atom_list
This is even more complex. On the one hand an atom list is expected, but also an atom is fine. So we have list and atom as relevant types:
8.14.3.2 Template and modes
op(+integer, +operator_specifier, #atom_or_atom_list)
8.14.3.3 Errors
...
f) Operator is neither a partial list nor a list nor
anatom— type_error(list, Operator).
g) An element E of the Operator list is neither avariable nor
an atom— type_error(atom, E).
It is equally plausible to produce atom for error f. On the other hand, both errors are equally applicable, and list is definitely the best for malformed lists like [a|nonlist], whereas atom is not necessarily better for 111 which might be an OCR error of [l].
callable_term
The corresponding type error contains callable. Like in
8.10.1.2 Template and modes
findall(?term, +callable_term, ?list)
8.10.1.3 Errors
...
b) Goal is neither a variable nor a callable term
— type_error(callable, Goal).
in_character_code
There is neither a corresponding type in 7.12.2 b, nor a domain in 7.12.2 c. But in 7.12.2 f it is defined for representation errors:
8.12.1.2 Template and modes
...
get_code(?in_character_code)
get_code(#stream_or_alias, ?in_character_code)
8.12.1.3 Errors
...
j) Code is an integer but not an in-character code (7.1.2.2)
— representation_error(in_character_code).
io_mode
This is listed in 8.1.2.1, contrary to the quoted text. It also appears in 7.12.2 c and is used:
8.11.5.3 Errors
...
h) Mode is an atom but not an input/output mode —
domain_error(io_mode, Mode).
character_code_list
Similar to write_options_list. However, it is erroneously mentioned in 7.12.2 c. That's an error in the standard which has been removed in Cor.3:2017.
Example:
conditions([-on(a, b)]).
I have searched tirelessly but fruitlessly for the meaning of this and the + prefix. You are my last hope.
No context is provided, so I'm supposing this might come from something in documentation.
If you read the introductory material in the Prolog manual (SWI, Gnu, or whichever) they describe teh conventions. The +, -, and ? are used as a convention in documentation to indicate whether an variable is an input or an output or a variable (either). For example, from the Gnu Prolog manual:
+: the argument must be instantiated.
-: the argument must be a variable (will be instantiated if the built-in predicate succeeds).
?: the argument can be instantiated or a variable.
So, for example, atom_length/2 is described as;
atom_length(+atom, ?integer)
Which means you must provide atom (it can't be a variable) and integer can either be a variable (in which case atom_length will provide a value) or it can be instantiated (in which case atom_length will indicate whether your query is true or false)`.
You don't normally use the - or + in your code in this sense, unless you really intend to have it there as part of your term. Considering the given example, it looks like it may have been an intended part of the term:
conditions([-on(a, b)]).
The list parameter consists of a term, when spelled out fully, is -(on(a,b)) (-/1 with parameter that's on/2). The - here doesn't provide any function, it just adds structure (the structure being a term with name - and parameter on(a,b)).