Hi @jan. Would your suggestion “[…] for the community would be to come up with a collectively maintained core documentation that includes the variations between predicates such as subtract/3 and the availability (built-in, (which) library) […]” align with PEP-like (or similar) repository? I understand that those documents would be useful and shared not only for SWI but for other Prolog systems. Actually, it looks a lot like Prolog Commons, with the difference that it is not necessary to share code, just specifications/documentation for the “common good”.
See also my comment on the setof/3 thread:
And yes, I think we have proved that common code is for now “a bridge too far”, so maybe shared documentation may be a meaningful intermediate step. Still, it won’t be easy to define the platform, how to bootstrap and how to build and maintain this. Most likely it is still a lot of work
I agree that this could be a very good way of making progress! It does seem more important to agree on what predicates do than to have common library code (although that would be great too, of course). We can use any format. If I remember well we actually made some progress with this in the Prolog Commons, before we ran out of steam…
*munity would be to come up with a collectively maintained core documentation that includes the variations between predicates such as [subtract/3]
All seems a good idea. My perspective on ISO is it all seemed to get into minutia on asserting exact behavior of all these weird uses, when as a programmer, my goal is to avoid weird uses where I’m never sure what to expect and focus on normal behavior. If the equivalent of CommonLISP never emerges, that’s expected. Yet to have a common central documentation that highlights main shared behavior and then the variations after sounds useful.
My wish list:
- Start small with very modest goals.
- Adopt some code of conduct https://www.contributor-covenant.org/ that makes sures that dialogue is constructive.
- Welcome all Prolog systems (both big, small, old, new, open-source, comercial, industrial, and academic systems). Every system has a raison d’être.
- Knowing what each system (precisely) provides is the best way for users to decide which system suits better their needs, or for system developers to decide which system they should contribute to.
I see two problems here, one that’s Prolog-specific and one that’s more general:
- The question whether a predicate should fail or raise an error
- The dreaded “implementation-defined behavior”.
The first problem is one of philosophy. I prefer raising an error because it can always be turned into failure by using catch/3, whereas failure doesn’t have a reason associated with it, so has less information to give to the programmer. But others may disagree (hello @ridgeworks !)
The second problem is one of “sufficient specificity”. C is the poster child for undefined behavior (e.g., what happens when you add 1 to a 0x07ffffff?), partly because it wants efficiency on all kinds of hardware and different choices have been made in hardware design (especially in the past – remember 1s complement arithmetic? 36-byte words? etc). This can be helped somewhat by “lint” programs, but for Prolog that requires quite a bit of type inferencing and static analysis (is Ciao-Prolog state of the art for this?)
For Prolog, there’s less of an efficiency issue, but there are still problems. The example of
setof(t,(L=2;L=1),L) has been raised (it fails on SWI-Prolog but gives an error on tau-Prolog). There might be underlying efficiency reasons for the two behaviors, and it would be a bad idea to penalize an implementation for the sake of “correct” handling of a pathological example. (Efficiency isn’t always important; but there’s no reason to be inefficient when there’s no need.) On the other hand, I doubt that I would ever see that problem because to me it’s a poorly written piece of code.
I don’t see any obvious solution to the problem of “undefined behavior”. C programmers have more-or-less learned to live with the “undefined” parts of the language and underlying libraries, although their solutions for code that needs to run on multiple platforms have become horribly baroque (
autoconf and tangled messes of
ifdefs, somewhat helped by
cmake). Possibly a set of pragmas could do some kind of source-level or compiler-level parameterization (e.g., “I want length/2 to throw an exception of the 1st parameter isn’t a list”), but even that is tricky (e.g., what do I want from
length(X,2.0), or do I even care?). It adds up to a lot of work by systems implementers (and documentation writers) for a small payoff.
Whether a predicate should fail or raise an error: For most predicates, I don’t care. Errors are for misuse, and I aim not to misuse things in my programming. Whether it fails or throws or halts, I will figure it out and change my program to not encounter that case.
That setof case is exactly what I consider pointless debate. Nobody writes programs with setof(t,…). The issue in C is mainly of two types: memory mismanagement (which largely doesn’t apply to Prolog) and integer size issues (which also don’t generally apply). What we have are mostly type mismatches. I am all in favor of predicate definitions being type-strict and mode-strict. I favor anything that enables type-correctness proving. I don’t care about programs that violate the expectations.
Possibly Novacore has a precedent in the form of init.pl
from SWI-Prolog. Its an interesting Kernel, that has no
dependency on some libraries. For example it does:
'$last'([H|T], Last) :- '$last'(T, H, Last). '$last'(, Last, Last). '$last'([H|T], _, Last) :- '$last'(T, H, Last).
On the other hand if I look at the Ciao Prolog distribution,
it gives me on GitHub, and lists.pl is the same lists.pl that
is also consumed by end-users:
+--- core +--- lib essential libraries +--- lists.pl
So SWI-Prolog has already a Novacore, and Ciao Prolog doesn’t.
Possibly there are more Prolog systems that are entangled as
Ciao Prolog is, all these Prolog systems can not easily
adopt a PEP that would suggest this and that lists library,
and where lists would live in the main name space. They could
adopt it when there would be some side library mechanism.
About side library mechanism, I wonder whether this makes
sense that, that expects_dialect/1 from SWI-Prolog sets the
expects_dialect(Dialect) :- [...] set_prolog_flag(emulated_dialect, Dialect).
So far I was writing portable code by doing some
current_prolog_flag(dialect, _) check. But given the above, it
is not portable enough to be run inside an emulation, if
the emulation doesn’t set the dialect flag, but another flag.
So today I made the flag
dialect mutable in my systems,
running some experiments with that. Lets see what happens…
Ciao Prolog is not as “entangled” as you may believe. Please ask us if you have any question regarding the Ciao design, specially before reaching wrong or inaccurate conclusions.
You can make the following test yourself.
Go to Ciao Prolog Playground, and try this:
?- use_module(library(lists)). Note: module lists already in executable, just made visible ?- nocontainsx([A,B,C],D). yes ?- nocontainsx([A,B,C],B). no
So some exotic list predicate
nocontainsx/2, from what it does,
maybe better belonging even to
library(idlists), is accessible by
the end-user, might even land in applications of the end-user.
But you cannot so easily change the module lists,
since the Ciao Prolog pl2wasm.pl depends on it:
:- module(pl2wam, [ [...] ], [assertions,nortchecks,dcg,datafacts]). :- use_module(library(lists), [append/3, length/2, dlist/3, list_lookup/3, contains1/2, nocontainsx/2, contains_ro/2, nonsingle/1, intset_insert/3, intset_delete/3, intset_in/2, intset_sequence/3]).
On the other hand Jan Ws init.pl can possibly be used to bootstrap
the Prolog system itself. I guess it can launch a new version of SWI-Prolog
with totally different list predicates, there is no dependency.
No need to refactor this Kernel when libraries change.
I see what you mean (sometimes your messages are a bit cryptic or our minds too limited…). I’ve created this issue redefine lists.pl (or other modules used in the compiler) · Issue #68 · ciao-lang/ciao · GitHub