Add `public/1` directive
Right now, there is no way in Scryer to declare a static, public procedure. This would be a welcome addition, e.g. with a public/1 directive.
It might be quite useful to go further and provide a way to declare that all procedures in a module are public.
Per ISO/IEC 13211-1:
7.5.3 Private and public procedures
NOTE --- An additional directive
public/1that specifies some user-defined procedures to be public would be an extension.[^1].
[^1]: > 3.70 extension: A facility provided by the processor that is not specified in this part of ISO/IEC 13211 but that would not cause any ambiguity or contradiction if added to this part of ISO/IEC 13211
Please make sure to consider existing discussion about public/1, notably https://github.com/mthom/scryer-prolog/issues/403#issuecomment-619568564.
It seems there's a fairly big terminology rift between ISO/IEC 13211-1 and SICStus in what they mean by "public". I think ISO "accessible" = SICStus "public".
4.11.2 Basic Concepts
A module defines a set of predicates, among which some have the property of being public. Public predicates are predicates that can be imported by other modules, which means that they can then be called from within those modules. Predicates that are not public are private to the module in which they are defined; that is, they cannot be called from outside that module
...
4.12.2 Dynamic and Static Procedures
All Prolog procedures are classified as being either static or dynamic procedures. Static procedures can be changed only by completely redefining them using the Load Predicates (see Section 4.3 [ref-lod], page 83). Dynamic procedures can be modified by adding or deleting individual clauses using the assert and retract procedures.
If a procedure is defined by loading source code, then it is static by default. If you need to be able to add, delete, or inspect the individual clauses of such a procedure, then you must make the procedure dynamic.
...
Dynamic procedures are implemented by interpretation, even if they are included in a file that is compiled. This means that they are executed more slowly than if they were static, and also that they can be printed using
listing/0. Dynamic procedures, as well as static procedures, are indexed on their first argument; see Section 9.5 [Indexing], page 364.
The primary use of public is for debugging and introspecting. Even just having some rough idea of what a predicate looks like is good enough, even if it’s not a faithful representation.
Please make sure to consider existing discussion about
public/1, notably #403 (comment).
1mo, how close is clause/2 to the original program? In other system some built-in optimizations are visible.
Variables might be renamed per spec and whitespace/comments stripped since these aren’t part of the term.
2do, how are term-expansions and goal-expansions handled? It seems several levels are necessary here.
These don’t exist in ISO prolog so the result is implementation-defined anyway.
3tio, what kind of declaration is used. It might be module-wise, maybe also with another option, that is, making predicates somehow invisible to outside callers or so...
Doesn’t matter. The “public” property is useless for any meaningful access control or encapsulation. It’s useful for debuggability and discoverability.
(Please note that I will comment on parts of your contributions one by one, otherwise responding takes too long. So I may or may not agree with what you write otherwise. And please do include ellipses when quoting the standard)
Per ISO/IEC 13211-1:
7.5.3 Private and public procedures
... % added ellipsis NOTE --- An additional directive
public/1that specifies some user-defined procedures to be public would be an extension.
Note that not every note is a good way to move forward. Think of suggested extension numbervars/3 which is unusable in the presence of constraints.
Footnotes
3.70 extension: A facility provided by the processor that is not specified in this part of ISO/IEC 13211 but that would not cause any ambiguity or contradiction if added to this part of ISO/IEC 13211.
Going first into terminology is usually a good way to access the codex. The entry you quote was there from early on (at least N53:1990-02). But only in DIS1:1994-06 there is 5.5 Extensions where many extensions are given taxatively. The terminology entry requires to "not cause any ambiguity or contradiction" which is a bit too strong. (But then no shall around.) Think of the predicate my_true/0 as an (implementation specific) extension. So what should now happen with
?- my_true.
existence_error(procedure,my_true/0) % 7.12.2 d
| true. % my meaning qua 5.5.9
This would be a contradiction without 5.5.9. To the programmer this is a clear warning: Don't rely on the inexistence of a predicate unless you have checked the accompanying documentation (5.4).
Added reference as #61.
1mo, how close is clause/2 to the original program? In other system some built-in optimizations are visible.
Variables might be renamed per spec and whitespace/comments stripped since these aren’t part of the term.
This is a consequence of the clause-interface and should come as no surprise to anyone. Also some transformations are due to term-to-body conversion which is currently not implemented in Scryer (#2811).
The problem arises with other transformations on the term (abstract syntax) level. Some such transformations are built-in and some induced by libraries. The example where I stumbled upon this was library(clpfd) for SWI, now library(clpz) in Scryer:
?- [user].
:- dynamic(p/1). % current way
p(X):- #X #> 0.
?- asserta((q(X):- #X #> 0)).
true.
?- clause(p(X),Body).
Body = (integer(X)->X>=0+1;_A=1,clpz:clpz_geq(#X,_A)).
?- clause(q(X),Body).
Body = (#X#>0).
So when compiled, goal expansion is applied. The expansion contains many impure non-monotonic constructs and thus such an expansion can no longer be used for a declarative explanation. On the other hand it is sometimes a very good idea to have such an expansion visible.
So there are different incompatible uses. What to do in such a situation? This was what I meant 2do:
2do, how are term-expansions and goal-expansions handled? It seems several levels are necessary here.
These don’t exist in ISO prolog so the result is implementation-defined anyway.
That is not a valid conclusion, provided you use "implementation defined" in the sense of the codex. Only those features that are explicitly stated as being implementation definable may be implementation defined. But this is somewhat off the subject. I hope you do agree that there are different incompatible uses. Currently.
3tio, what kind of declaration is used. It might be module-wise, maybe also with another option, that is, making predicates somehow invisible to outside callers or so...
Doesn’t matter. The “public” property is useless for any meaningful access control or encapsulation. It’s useful for debuggability and discoverability.
The most important use I see are meta-interpreters in their various incarnations. And there, having to declare each and every predicate as public would be quite tiresome.
please do include ellipses when quoting the standard
:+1:
Trying to understand Prolog by reading the ISO spec is probably going to be part of my supervillain origin story!
I don't quite understand yet what "N53:1990-02" or "DIS1:1994-06" mean - is there a place where these documents are listed by reference number? The website https://www.complang.tuwien.ac.at/ulrich/iso-prolog/ is a firehose of info (thank you!), my biggest obstacle is I don't understand what there is spec or likely to become spec.
Note that not every note is a good way to move forward. Think of suggested extension
numbervars/3which is unusable in the presence of constraints.
Acknowledged. I'm also not clear whether public/1 is actually a good idea.
My thought chain is thus (and seems similar to the same thought process as @triska went down):
- Scryer has no
help/1predicate. To understand a predicate, I reach forclause/2(orlisting/1, which is written in terms ofclause/2).- note: in swipl, while e.g.
clause(write(_,_),C)fails with an error,listing(write/2)print the non-representative but informative text% Foreign: system:write/2.
- note: in swipl, while e.g.
- The
clause/2predicate throws the unhelpfulpermission_error(access, private_procedure, Pred)in almost all cases. Hereditarily, this means introspection likelisting/1throws the same error. - This indicates that the problem is the procedure is private; the obvious way to fix this is to make the procedure public instead.
- The
dynamic/1directive is about whether a procedure is mutable (its clauses can be written). What I want is the ability to simply make a procedure inspectable (its clauses can be read). There are many ways to fix this situation, and I thoughtpublic/1is the easiest, least surprising way that is spec-compatible.
There certainly other ways forward.
Since "dynamic" implies "public", it would be perfectly sufficient to make public/1 a synonym for dynamic/1 (with the caveat that it's an implementation detail and trying to alter so-declared procedures at runtime might emit a warning or error in future versions; or it might just be advisory).
The problem arises with other transformations on the term (abstract syntax) level. Some such transformations are built-in and some induced by libraries. The example where I stumbled upon this was
library(clpfd)for SWI, nowlibrary(clpz)in Scryer:
?- [user]. :- dynamic(p/1). % current way p(X):- #X #> 0. ?- asserta((q(X):- #X #> 0)). true. ?- clause(p(X),Body). Body = (integer(X)->X>=0+1;_A=1,clpz:clpz_geq(#X,_A)). ?- clause(q(X),Body). Body = (#X#>0).
So when compiled, goal expansion is applied. The expansion contains many impure non-monotonic constructs and thus such an expansion can no longer be used for a declarative explanation. On the other hand it is sometimes a very good idea to have such an expansion visible.
If predicates are public but static, then the processor can choose to make such an expansion visible (since you're sure clauses won't be added or changed). If you only have dynamic, the processor's hands are tied; you cannot expand since the meaning of a term can change by redefining predicates.
The most important use I see are meta-interpreters in their various incarnations. And there, having to declare each and every predicate as public would be quite tiresome.
Great. I'd be in favor of a flag that allows us to break with the spec and make all predicates public. But that's not what I'm proposing here.
Trying to understand Prolog by reading the ISO spec is probably going to be part of my supervillain origin story!
Did you start with the scope? One always has to start with the scope when reading a standard! In 1 Scope, just before 1.1, there is one sentence of relevance ...
I don't quite understand yet what "N53:1990-02" or "DIS1:1994-06" mean - is there a place where these documents are listed by reference number?
Document register.
my biggest obstacle is I don't understand what there is spec or likely to become spec.
The answer:
Here are current working documents for ISO/IEC JTC1 SC22 WG17.
- Scryer has no
help/1predicate. To understand a predicate, I reach forclause/2(orlisting/1, which is written in terms ofclause/2).
This is what documentation is for. I never used clause/2 for that purpose. You might see things you do not need to understand, like practically all of the clpz implementation.
Regarding phrasings such as "a flag that allows us to break with the spec", I note for example:
5.5.8 Flags A processor may support one or more additional flags (7.11) as an implementation specific feature.
A conforming implementation can in many ways go far beyond the bare minimum that the standard requires.
Trying to understand Prolog by reading the ISO spec is probably going to be part of my supervillain origin story!
Did you start with the scope? One always has to start with the scope when reading a standard! In 1 Scope, just before 1.1, there is one sentence of relevance ...
I think I'm too thick to understand what you're trying to tell me.
I don't quite understand yet what "N53:1990-02" or "DIS1:1994-06" mean - is there a place where these documents are listed by reference number?
Document register.
This? I figured "N53:1990-02" was some sort of URL but now I see "N53" is probably the reference number and 1990-02 the publication year and month. Maybe DIS1:1994-06 is synonymous with N128 "Prolog --- Part 1, General core -- Draft International Standard (ISO/IEC DIS 13211-1)".
Some documents are hyperlinked but I can't figure out where to read the ones that aren't (such as N53).
my biggest obstacle is I don't understand what there is spec or likely to become spec.
The answer:
Here are current working documents for ISO/IEC JTC1 SC22 WG17.
That link takes me to a login page to which I don't have credentials and no signup link.
Putting aside the question of what is likely to become spec, is it correct to say the following?:
- ISO/IEC 13211 parts 1 and 2 and corrigenda are the total spec
-
term_expansion/2anduse_module/2are not included in the spec as it exists today - (per 13211-1 5.5.9) Additional built-in predicates are an implementation-specific feature
- (per 13211-1 5.1 e) A conforming Prolog processor must offer a strictly conforming mode which rejects goals that depends on
term_expansion/2anduse_module/2.
This is what documentation is for. I never used
clause/2for that purpose. You might see things you do not need to understand, like practically all of theclpzimplementation.
Thank you. I cannot stress enough how useful it is to hear statements like these that set expectations and recommend usage (even if the documentation has some pretty big holes in it, for now).
Did you start with the scope? One always has to start with the scope when reading a standard! In 1 Scope, just before 1.1, there is one sentence of relevance ...
I think I'm too thick to understand what you're trying to tell me.
If you want to discuss the standard you need to have it in front of you. Thus you need to be able to read in particular the last sentence of the NOTE in 1 Scope.
Some documents are hyperlinked but I can't figure out where to read the ones that aren't (such as N53).
And you won't get them since these are previous draft versions. In the past some individual wrote up an intermediary summary which had the detrimental effect that some implementers used it as reference — just to save the USD 30 (now 60) for getting the official Part 1. So let's keep that out of your mind. My point here was just that the missing reference (#61) is missing for a reason.
Putting aside the question of what is likely to become spec, is it correct to say the following?
You are using your terminology which makes it difficult to communicate (think of your usage of "implementation defined"). "spec", where do you have it from?
As for the formal part, refer to the official SC22 page. The working documents are in a much, much earlier stage.
@triska
Regarding phrasings such as "a flag that allows us to break with the spec", I note for example: ... A conforming implementation can in many ways go far beyond the bare minimum that the standard requires.
True, I was being cheeky with my wording. But anyway, I was referring to the quote "a static user-defined procedure shall be private by default." I don't know whether a flag that made all user-defined procedures public (or dynamic) would be permissible.
@UWN
Did you start with the scope? One always has to start with the scope when reading a standard! In 1 Scope, just before 1.1, there is one sentence of relevance ...
I think I'm too thick to understand what you're trying to tell me.
If you want to discuss the standard you need to have it in front of you. Thus you need to be able to read in particular the last sentence of the NOTE in 1 Scope.
Ah, I thought you were talking about part 1 where it says "This part of ISO/IEC 13211 does not specify ...". You meant part 2, section 1 "This part of ISO/IEC 13211 is intended for use by implementors and knowledgeable programmers and is not a tutorial." :-).
The reason I'm looking at the spec is because I'm trying to understand what Scryer ought to do. I can read tutorials or SWI/SICStus/Ciao/etc. manuals but then it's not clear what parts I can transfer to Scryer. To quote Segal's law: "A man with a watch knows what time it is. A man with two watches is never sure."
Some documents are hyperlinked but I can't figure out where to read the ones that aren't (such as N53).
And you won't get them since these are previous draft versions. In the past some individual wrote up an intermediary summary which had the detrimental effect that some implementers used it as reference — just to save the USD 30 (now 60) for getting the official Part 1. So let's keep that out of your mind. My point here was just that the missing reference (#61) is missing for a reason.
Very fair. I inferred you provided citations is so I could research further and add context to my [mis]understanding.
Putting aside the question of what is likely to become spec, is it correct to say the following?
You are using your terminology which makes it difficult to communicate (think of your usage of "implementation defined"). "spec", where do you have it from?
You're right. I'll try to clarify:
- ISO/IEC 13211 parts 1 and 2 and corrigenda are the total spec
I mean by this is "there is no well-recognized standard for Prolog that I'm overlooking, right? I have seen IEC 13211 part 1 (including corrigenda 1-3) and part 2. There is no other mandatory background reading or document I need to have in front of me if I want to check whether Scryer Prolog meets the 'Prolog ISO Standard' (besides Scryer's own source code and documentation)."
I used the term "the spec" here because I'm not sure whether Scryer is trying to comply with ISO/IEC 13211-1 or with "ISO Prolog" in a broader sense, which might include some of ISO/IEC 13211-2.
Part 1 section 5.3 says that "A strictly conforming Prolog goal is one whose execution is defined by the constructs specified in this part of ISO/IEC 1321, and the implementation defined features supported by the processor". Part 2 section 4.3 says "A strictly conforming Prolog goal is one whose execution is defined by constructs specified in this part of ISO/IEC 13211 and ISO/IEC 13211-1, and the implementation defined features specified by this part of ISO/IEC 13211."
Succinctly,
- May a processor with a "strictly conforming mode" per ISO/IEC 13211-1 allow using
predicate_property/2since it is NOT implementation-specific in part 2? - Should a processor with a "strictly conforming mode" per ISO/IEC 13211-2 provide a second "strictly conforming mode" to comply with ISO/IEC 13211-1 5.1 e?
- term_expansion/2 and use_module/2 are not included in the spec as it exists today
You can read "the spec" here as either ISO/IEC 13211-1 or ISO/IEC 13211-2.
- (per 13211-1 5.5.9) Additional built-in predicates are an implementation-specific feature
- (per 13211-1 5.1 e) A conforming Prolog processor must offer a strictly conforming mode which rejects goals that depends on term_expansion/2 and use_module/2.
Does this conclusion necessarily follow?
You meant part 2, section 1 "This ... is not a tutorial." :-).
But then, this is not normative either, just a note "in order to help readers find their way around."
... [spec continued] ...
You deleted the reference to SC22 where you get the most up to date status stage. In fact, I received the information on the latest progress only a day later. So use the link above such that you know how to get that information without me.
... [spec continued] ...
You deleted the reference to SC22 where you get the most up to date ~status~ stage. In fact, I received the information on the latest progress only a day later. So use the link above such that you know how to get that information without me.
Yes! Sorry I did not acknowledge this, that page did indeed tell me that I’m not missing any pertinent specifications. Thank you!
The sole remaining questions, that I think I cannot answer myself:
- May a processor ~~with a~~ under its "strictly conforming mode" per ISO/IEC 13211-1 allow using
predicate_property/2since it is NOT implementation-specific in part 2?- Should a processor with a "strictly conforming mode" per ISO/IEC 13211-2 provide a second "strictly conforming mode" to comply with ISO/IEC 13211-1 5.1 e?
You deleted the reference to SC22 where you get the most up to date
statusstage. In fact, I received the information on the latest progress only a day later. So use the link above such that you know how to get that information without me.Yes! Sorry I did not acknowledge this, that page did indeed tell me that I’m not missing any pertinent specifications.
Not. Read again. What is forthcoming?
The sole remaining questions, that I **** think I cannot answer myself:
You are driving yourself into a corner. I still stand by what I said originally and on SO. In the meantime you pointed out further inconsistencies but which do not affect my point.
"A mode" can mean a lot of things. The best and most economic interpretation is to realize (part of) that mode with modules. And, it certainly does not make sense to disable the module system.
You deleted the reference to SC22 where you get the most up to date ~status~ stage. In fact, I received the information on the latest progress only a day later. So use the link above such that you know how to get that information without me.
Yes! Sorry I did not acknowledge this, that page did indeed tell me that I’m not missing any pertinent specifications.
Not. Read again. What is forthcoming?
Yes, there is ISO/IEC TS 13211-3 "Part 3: Definite clause grammar rules as an extension of ISO/IEC 13211-1" which is likely to be of future interest.
The sole remaining questions, that I **** think I cannot answer myself:
You are driving yourself into a corner. I still stand by what I said originally and on SO. In the meantime you pointed out further inconsistencies but which do not affect my point.
The module standard ISO/IEC 13211-2:2000 permits several realizations. The document itself gives two instances in 6.4.4.1 and 6.4.4.2. This is one of the bigger problems for its adoption. In fact, even the Quintus/SICStus based module system could be seen as a further instance.
Sorry, what does "realization" mean? I don't find that defined anywhere.
-
I think ISO/IEC 13211-2 6.4.4.2 is conforming module text that may be accepted by a compliant processor and MUST be rejected in a strictly conforming mode (as defined by either ISO/IEC 13211-1 or 13211-2).
-
I think it is wrong to say: those are both instances of strictly conforming module text.
-
I think it is wrong to say: a processor can be ISO/IEC 13211-2 compliant yet reject strictly conforming module text or a strictly conforming Prolog goal.
"A mode" can mean a lot of things. The best and most economic interpretation is to realize (part of) that mode with modules. And, it certainly does not make sense to disable the module system.
I mean in the sense of "A conforming Prolog processor shall ... Offer a strictly conforming mode which shall reject the use of an implementation specific feature in Prolog text or while executing a goal." I assumed that the mode must be opt-in (for example, it makes no sense to say it's in that mode unless given non-strict text, since then it couldn't reject anything!)
I thought Scryer Prolog intended to make strictly conforming mode the default mode of operation. I definitely never had a clear sense if that meant strictly conforming to ISO/IEC 13211-1 or strictly conforming to ISO/IEC 13211-2.
You deleted the reference to SC22 where you get the most up to date ~status~ stage. In fact, I received the information on the latest progress only a day later. So use the link above such that you know how to get that information without me.
Yes, there is ISO/IEC TS 13211-3 "Part 3: Definite clause grammar rules as an extension of ISO/IEC 13211-1" which is likely to be of future interest.
This is of interest now. For the moment, I am aware of one issue in Scryer. And I believe there are more of that kind. And in general, all things related to term-to-body conversion. Or think of the so far failed attempt to expand library(reif) in a fully conforming way.
The sole remaining questions, that I **** think I cannot answer myself:
You are driving yourself into a corner. I still stand by what I said originally and on SO. In the meantime you pointed out further inconsistencies but which do not affect my point.
The module standard ISO/IEC 13211-2:2000 permits several realizations. The document itself gives two instances in 6.4.4.1 and 6.4.4.2. This is one of the bigger problems for its adoption. In fact, even the Quintus/SICStus based module system could be seen as a further instance.
Sorry, what does "realization" mean? I don't find that defined anywhere.
- I think ISO/IEC 13211-2 6.4.4.2 is conforming module text that may be accepted by a compliant processor and MUST be rejected in a strictly conforming mode (as defined by either ISO/IEC 13211-1 or 13211-2).
At least you agree now that 6.4.4.2 shows some conforming text. Even if you want it to be rejected sometimes...
"A mode" can mean a lot of things. The best and most economic interpretation is to realize (part of) that mode with modules. And, it certainly does not make sense to disable the module system.
I mean in the sense of "A conforming Prolog processor shall ... Offer a strictly conforming mode which shall reject the use of an implementation specific feature in Prolog text or while executing a goal." I assumed that the mode must be opt-in (for example, it makes no sense to say it's in that mode unless given non-strict text, since then it couldn't reject anything!)
Yes, opt-in. Most of that "mode" can be realized by not using certain modules.
I thought Scryer Prolog intended to make strictly conforming mode the default mode of operation. I definitely never had a clear sense if that meant strictly conforming to ISO/IEC 13211-1 or strictly conforming to ISO/IEC 13211-2.
Scryer is very close to a strictly conforming mode — compared to other systems. But you insist on excluding the module system from it. That does not make sense.
This is of interest now. For the moment, I am aware of one issue in Scryer. And I believe there are more of that kind. And in general, all things related to term-to-body conversion. Or think of the so far failed attempt to expand
library(reif)in a fully conforming way.
👍
At least you agree now that 6.4.4.2 shows some conforming text. Even if you want it to be rejected sometimes...
I miswrote that. It was conforming prolog text per ISO/IEC 13211-1.
It's not clear to me whether it ever was considered "conforming module text" per ISO/IEC 13211-2, given that the processor never adopted the strictly conforming part of ISO/IEC 13211-2.
(The definition of "implementation specific" in part 1 is with respect to a conforming processor. It's not clear whether, (1) that requires an actual conforming processor or just a hypothetical one (2) If it requires a conforming processor, it's not clear if that means conforming to part 1 or conforming to part 2.)
Yes, opt-in. Most of that "mode" can be realized by not using certain modules.
I mean some sort of command-line parameter, config file, or set_prolog_flag/2. Simply declining to use certain modules or features wouldn't make sense as a means of opting in, since it wouldn't cause the processor to "reject" anything.
Scryer is very close to a strictly conforming mode — compared to other systems. But you insist on excluding the module system from it. That does not make sense.
- It is pointless to be able to turn off implementation-specific module features if Scryer is aiming to be ISO/IEC 13211-2 compliant, unless and until it supports a useful subset of strictly conforming module text.
- It is mandatory to be able to turn off implementation-specific features (including module features) if Scryer hopes to be ISO/IEC 13211-1 compliant.
I mean some sort of command-line parameter, config file, or set_prolog_flag/2. Simply declining to use certain modules or features wouldn't make sense as a means of opting in, since it wouldn't cause the processor to "reject" anything.
Sorry, now you lost me completely. Just consider the typical (currently) implementation specific predicate length/2 which is commonly present. Now what should happen with it in strict mode, according to you?
Now what should happen with it in strict mode, according to you?
I think the standard is pretty clear that it should always be rejected.
5.1e) Offer a strictly conforming mode which shall reject the use of an implementation specific feature in Prolog text or while executing a goal.
5.5.9 Built-in predicates A processor may support one or more additional built-in predicates (8) as an implementation specific feature.
I think you are pointing out that this doesn't give any way for implementations to "grow" the strict mode with future ISO extensions (length/2 is part of the Prolog Prologue, which still isn't standardized), which is true. I think that if anything this is a problem in the standard by not providing a way to allow it.
An idea is to give an implementation defined (and therefore allowed in strictly conforming mode) way to "opt-in" to things that are not yet ISO. The way C implementations do it is to have a flag like -std=c2y in the compiler for "conform to the next standard". CLI flags are implementation defined so that could be a way. A way to do that in Prolog text would be ideal, but I can't think of anything adequate. It seems that use_module/1 is intended to be that way to opt-in to implementation specific features with an implementation defined one, the only problem being that use_module/1 seems to be implementation specific (in 13211-1 and 13211-2).
It seems you all are overinterpreting what reject here means. So let's consider the following Prolog text:
p :- length(_,_).
What should now happen when preparing it for execution in strict mode? And what when then executing p/0?
My guess is that it is prepared normally, but when executing and reaching length(_,_) it should either fail or throw an existence error. Is that not what "reject" means in this context? There doesn't seem to be any definition of "reject" in 13211-1.
My guess is that it is prepared normally, but when executing and reaching
length(_,_)it should either fail or throw an existence error.
When executing, it must produce an existence error. (Why fail??)
Is that not what "reject" means in this context? There doesn't seem to be any definition of "reject" in 13211-1.
What should it reject? p :- length(_,_). is valid Prolog text. But in strict mode you could now add your own definition for length/2.
The whole point of this example is just to point out that it suffices to put predicates that are "implementation specific" extensions into modules. And strict mode (w.r.t. such extensions) is already, when you just start up the system without any extra modules loaded.
The whole point of this example is just to point out that it suffices to put predicates that are "implementation specific" extensions into modules. And strict mode (w.r.t. such extensions) is already, when you just start up the system without any extra modules loaded.
Yes, that is fine, I'm completely in favor of that and think it's a good way to do it. My problem with that is that the way to load modules in Scryer, :- use_module(_)., is implementation specific and therefore should be rejected in strict conforming mode. use_module/1 is not defined in 13211-1, it's corrigendums, or 13211-2, so it's an "additional directive":
5.5.5 Directives A processor may support one or more additional directive indicators (7.4.2) as an implementation specific feature.
Is there any tricky bit with what "reject" means in the case of a directive? I suppose that in this case it should be rejected during preparation of the text for execution.
Sorry, now you lost me completely. Just consider the typical (currently) implementation specific predicate
length/2which is commonly present. Now what should happen with it in strict mode, according to you?
That's a very good question! It depends.
- Is
length/2specified by the processor as a built-in predicate? If so the behavior depends on the value of theunknownflag. - Is
length/2defined as a user-defined procedure in strictly conforming, non-module, Prolog text? If so, then it will be in the complete database at runtime (in theusermodule, most likely) and the call will succeed. I think it quite natural for a processor to ship with, and implicitly include by default, standard-conforming "library" texts into the complete database as part of the "user environment" mentioned by 13211-1. - Is the usage of
length/2inside a module body, butlength/2is not made visible via animport/1orimport/2directive? If so, the behavior depends again on the value of theunknownflag. The module spec defines the visible database such that a new module has no visible user-defined procedures.
@bakaq, so now back to modules. And 6.4 which talks about "some other implementation defined method" (6.4 end), and then in 6.4.4.2 illustrates what it meant by that (IF Prolog examples). So what do we see there? Apparently implementation defined features. And if 6.4.4.2 is "an alternate mechanism" what else could one put here? Why not, again another system?
Not very satisfying. But then, look what systems there were. Part 1 is 1995. That it was published without modules was not the idea in 1987. IF is 1996-04 together with its module system. Prolog IV is soon thereafter. Also GNU. But otherwise Part 1 is ignored until the wakeup call. During that time the module standard was developed with very low participation and presumably exhaustion. And then in the very last moments an effort to have at least something.
Effectively, modules occupied WG17 throughout its existence. The major conflict was name based systems (sometimes called atom based) vs. predicate based systems. And lots of efforts to reconcile them. Not even within Quintus (predicate based, what we have in Scryer) was there ample harmony. They hid their own precious treasure (call/N) as much as they could, putting it into some less documented library (it was there from at least 1.5 on - before modules came in 2). And meta_predicate declarations without the integers make this system look very dumb compared to name based ones. No easy cross referencing possible. And it was not even appreciated when SICStus and Quintus were merged into SICStus 4 in 2006. In fact, the integers were removed and only reintroduced in 2011 (see this). 2011!
Thank you for the in-depth historical explanation!
And 6.4 which talks about "some other implementation defined method" (6.4 end), and then in 6.4.4.2 illustrates what it meant by that (IF Prolog examples). So what do we see there? Apparently implementation defined features. And if 6.4.4.2 is "an alternate mechanism" what else could one put here? Why not, again another system?
This seems to ignore the context of this mention of "implementation defined" (which is in fact the only relevant mention of "implementation defined" in the entirety of 13211-2 as far as I've been able to find).
6.4 Context sensitive predicates [...] When the flag colon_sets_calling_context is true the calling context can be set explicitly by using the infix operator ‘:’. When the flag colon_sets_calling_context is false some other implementation defined method for explicitly setting the calling context shall be provided.
This seems to only be about setting the calling context, not the whole module system. The example given in 6.4.4.2 does make use of this implementation defined feature, but it also makes use of implementation specific features such as :- meta [interpret/0]., therefore making it conforming but not strictly conforming (5.1e). It certainly doesn't seem to imply that any set of module system interface directives with "similar semantic vibes" is strictly conforming, which is what I really care about here. Namely, should use_module/1 be allowed in the strictly conforming default mode of Scryer? If there is no justification for it's implementation definedness, then it's implementation specific and should be rejected, which I interpret as throwing an error when preparing text for execution.
The only explicit mention of "implementation specific" that I could find in 13211-2 is for dynamic creation and abolition of modules.
4.5.1 Dynamic Modules A Prolog processor may support additional implementation specific procedures that support the creation or abolition of modules during execution of a Prolog goal.
Everything else defined in 13211-2 seems to be required, given the extensive use of the word "shall" in almost every definition in the entire document (assuming it has a similar meaning to RFC 2119), though I'm not really sure if this actually matters if a system just wants to use part of 13211-2 to justify having modules at all and not actually fully comply to it.
re: https://github.com/mthom/scryer-prolog/issues/2933#issuecomment-2848891395
But otherwise Part 1 is ignored until the wakeup call. During that time the module standard was developed with very low participation and presumably exhaustion. And then in the very last moments an effort to have at least something.
Thank you! This history lesson is VERY appreciated and I appreciate so much the context this gives. I'm reading through this several times.
Effectively, modules occupied WG17 throughout its existence. The major conflict was...
I believe it! While the debates may have been about name-based systems vs predicate-based systems, and fancy features in metapredicate declarations (both things I don't grok yet), it's a damn shame that the module systems were syntactically incompatible.
If instead systems had adopted a common set of directives (e.g. module/2 use_module/2 from SICStus, or e.g. module/1, export/1, ..., end_body/1), you would at least be able to write a table contrasting their semantic differences (like the one at https://www.complang.tuwien.ac.at/ulrich/iso-prolog/length) and assemble a set of conformity test cases.
I'm not really sure if this actually matters if a system just wants to use part of 13211-2 to justify having modules at all and not actually fully comply to it.
I think this is an important point. Part 2 does NOT relax any requirements of part 1. If a processor does not implement part 2, there's NO benefit that your processor-specific dialect is conforming module text. (and it's still dubious to me whether it can be correctly called "conforming module text").
The only explicit mention of "implementation specific" that I could find in 13211-2 is for dynamic creation and abolition of modules.
Unlike user predicates, there doesn't seem to be a way to define a new directive. So you could not define :- module(_,_) in user code which could work in strict mode (like you could with length(_,_)).
But I think it's possible that Scryer could support an implementation-specific module/2 directive that emulates SICStus but is defined in terms of part 2 directives.
This seems to only be about setting the calling context, not the whole module system. The example given in 6.4.4.2 does make use of this implementation defined feature, but it also makes use of implementation specific features such as
:- meta [interpret/0]., therefore making it conforming but not strictly conforming (5.1e).
There are two aspects interwoven here.
1mo, what you call here implementation specific features are necessary to use the implementation defined mechanism. So the mechanism must be there, but — sorry — you cannot use it in strict mode. That is absurd. So also the features around, like here the directive (meta)/1 must be implementation defined.
Insisting on your view, is like insisting prior to Cor.3 C2 that in strict mode there is exactly one valid Prolog text.
2do, now assuming that the directives use_module/1/2 are accepted in strict mode, consider
:- use_module(library(lists)). % knowing it exports length/2
q :- length(_,_).
So clearly an implementation specific length/2 is now used. On the other hand, if the module would be again a user provided Prolog text, this would be fine. It depends on the indicated library/module whether or not this is accepted in strict mode. So this decision needs to be made when processing the directive. And yes, on that level one might allow certain libraries explicitly.
But what is most important is that the remaining library code is unaffected by this. In the versions 3 prior to 4 of SICStus, a flag permitted to switch between pre-ISO and ISO meaning of built-ins. That was really not a good idea since many built-ins had lots of such runtime tests in it. I have somewhat the suspicion that IF has a similar mechanism, although there is no way at runtime to switch between these modes. Only a command line switch.
1mo, what you call here implementation specific features are necessary to use the implementation defined mechanism. So the mechanism must be there, but — sorry — you cannot use it in strict mode. That is absurd. So also the features around, like here the directive (meta)/1 must be implementation defined.
Huh... I see now what you mean. However, for me at least, this seems more like an oversight of the specification that should be corrected with a corrigendum than an intentional breach that opens the Pandora's box for any possible module implementation to be implementation defined.
Insisting on your view, is like insisting prior to Cor.3 C2 that in strict mode there is exactly one valid Prolog text.
I would indeed insist on this (no spaces allowed, wow). That's why a corrigendum was needed no? Am I just being too pedantic here?
As for the 2nd point, my intention was specifically to allow some way of opting out of strict conforming mode in an implementation defined way (doesn't need to be use_module/1, I'm focusing on this one because it seems to be the current intended mechanism to do that).
The way you describe seems to assume that an implementation defined feature shouldn't activate an implementation specific feature, which makes complete sense. I understand that mixing implementation defined and implementation specific features has a lot of problems and so maybe this shouldn't be allowed at all. However that would mean that it would be really impossible to get out of strict conforming mode from inside of Prolog, because any way to exit would need to be implementation specific and therefore not allowed. One would need to "pre-choose" the mode in a CLI flag, before even starting the processor.
In that way current default Scryer Prolog is very close to strict 5.1e mode, but not quite because there are still implementation specific features (use_module/1) to allow getting out of it. This is fine, and indeed apparently better than any other implementation, but if this is indeed the case then I think we shouldn't lie about Scryer Prolog being strictly conforming. Again, maybe I'm being too pedantic here.