Which meanings of "type" are used in the standard? - iso-prolog

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.

Related

What is the meaning of a double slash `//` after the predicate name in Prolog, appearing in the context of DCGs?

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.

Is there a Prolog name for moving a functor name in to an argument?

It is not uncommon to see data in Prolog written with a functor, e.g.
note("This is a note")
but Prolog can also process the data with the name moved to an argument, e.g.
(note,"This is a note")
When moving the data name from the functor into an argument, is there a name used to describe this process?
I have some code that will have the data converted as such and would like to include in the documentation a standard name to describe this change if it exist.
EDIT
The current specific reason for doing this is so I don't have to use =../2 and can also make comparison on many datum with anonymous variable, e.g.
(_,A,B,C)
or write more general predicates, e.g.
do(_)
do(_,A)
do(_,A,B)
instead of
do(note(A))
do(note(A,B))
do(note(A,B,C))
do(comment(A))
do(comment(A,B))
do(comment(A,B,C))
do(text(A))
do(text(A,B))
do(text(A,B,C))
EDIT
Below is a comment by #repeat with reasons not to do what is demonstrated in this question by changing a compound term note(A,B) into a comma list (A,B), as opposed to a regular list [A,B]. It is good advise but sometimes there are reasons for breaking such advise. I can not say at present for my current need if doing this in Prolog is one of those cases, but as the question asks, it would be nice to have a name for the process so that it can be searched for research.
#repeat You can edit this and add notes as it is all Creative Commons.
Actually, (note, "this is a note") is a term with functor , and arity 2 (first argument note, and second argument "this is a note").
You can see this issuing the following queries:
?- write_canonical(note("This is a note")).
note("This is a note")
?- write_canonical((note,"This is a note")).
','(note,"This is a note")
So what you are doing by "moving" the principal functor of a term of arity N to a term of arity N+1 with principal function , adding the previous functor name as the first argument and shifting the other arguments is some sort of generalization, though I don't know if there is a more suitable name for this.
You could see it as a restricted way to write an applicative encoding of a higher-order logic fragment into first order logic. An applicative encoding uses constants to represent functions and uses a binary function symbol app to express that f is applied to an argument list. For example, the applicative encoding of f(g(a),b) is app(f, [app(g,[a]),b ]). In your case, the ,/N operator plays this role but as you have probably noticed, without an argument list you need to know the number of arguments when you are matching against such a term.
An example where this encoding is used in a Prolog context is the higher-order automated theorem prover input format TPTP THF. They use an infix operator # to represent application. There, they also use the standard encoding which uses nested apps. The term representation is not as beautiful (the example term is written (f # (g # a))) # b) but it has the advantage that constants only have one representation. With the list encoding, you have to take into account that c = app(c, []).

If and cond as special forms

Consider these two paragraphs from SICP:
This construct is called a case analysis, and there is a special form
in Lisp for notating such a case analysis. It is called cond (which
stands for “conditional”), and it is used as follows:
...
This uses the special form if, a restricted type of conditional that
can be used when there are precisely two cases in the case analysis.
What does type mean in this context (restricted type of conditional)? Does it mean:
"if" is a type of "cond"? Because the sentence states "there is a special form", so there is only one special form because "if" is one type of "cond".
Both "if" and "cond" are unrelated. They are both conditionals. If this is correct, why does this sentence say "there is a special form" like it is only one?
In " if [is] a restricted type of conditional", I believe "conditional" doesn't mean specifically cond; it means "conditional statement / expression", in general.
So there are two, cond and if. Each can be defined in terms of the other, so a given implementation may choose to have only one of them as a primitive, defining the other in terms of it; or the implementation can choose to have both of them as primitive special forms.
Special forms are handled specially by the interpreter (compiler) itself.
Macros also can be used for that. They won't be handled by the interpreter itself then, but rather by its macros-handling mechanism.
So if is a conditional; cond is a conditional; cond can have any number of clauses; if must have exactly two (or one or two, depending on the standard) clauses; all the rest is just English. :)

Prolog predicate argument descriptors [duplicate]

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

Meaning of instantiation mode indicators in arguments of Prolog predicates

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

Resources