Careful with subtract/3

BTW, If you want to talk about the limitations and weak points of Ciao Prolog, we can tell you, we are aware of them. If you want us to explain why we believe that some decisions in Ciao are good, we can do it. If something is not well documented, file and issue or better open a pull request. We are open source and admit contributions.

Exactly! There is definitely an (optimized) WAM there, and there is of course resolution, but you are not forced to use the the ISO built-ins if you do not wish to. And this happens on a per module basis. I.e., you can have all your program modules be ISO and then have a particular module in which you are using a new type of arithmetic instead of is/2, or functional syntax, or… It is additional functionality beyond ISO, with the quirk that you can add or subtract the ISO stuff at will. This is not meant of course for applications that want to be portable, where you probably want to stick to standard Prolog, but it is very useful to design new languages, future directions for Prolog, etc. and play with them in a module without affecting the overall system.

(Nothing of importance here)

Yes, you can do it no problem. You will get:

{Compiling /
WARNING: (lns 2-5) Unqualified predicate call to tab/1 assumed to local version, calls to predicate imported from io_basic must be qualified

which means exactly that, i.e., that now you have two versions of tab/1, a local one and the one imported from the libraries. If you want to be able to call the one you defined from the top level, export it from the module (here

:- module(_,[main/0,tab/1]).

main :- 

tab(X) :- Y is X, io_basic:tab(Y).

and now:

?- use_module('/').
{Compiling /
WARNING: (lns 2-5) Unqualified predicate call to tab/1 assumed to local version, calls to predicate imported from io_basic must be qualified
?- draft:tab(3+2), write(a).

If you want to avoid the warning when compiling the module use:
:- redefining(tab/1).

In the top level:

?- use_module('/').

?- draft:tab(3+2), write(a).

[ A brief reading guide for this thread, or ‘how we ended up here?’:

  • You mentioned that it would be hard for Ciao to change the lists module.
  • We explained that the Ciao design make this simple (so we can do it, but we need agreements on the changes because adding one predicate here may break some other source there)
  • To explain the Ciao design we need to say that in Ciao very few predicates are “builtin” (we can enable/disable a lot of things in the language). This is irrelevant for the original discussion but needed, since you said that doing changes in Ciao would be hard. ]

:slight_smile: :slight_smile: Nice summary @jfmc, thanks!

Btw, I checked and this idlists library module from CIao is at least 22 years old, probably more (I did not have time to check back before 2000).

(Nothing of importance here)

Yes it works unchanged in the new SWI-Prolog WASM, thats wonderful!
Just copy paste from rextester to the new SWI-Prolog WASM:

I guess Jan W. is the only guy that can make things work. Who helped
him exactly? What are the exact credits for the SWI-Prolog WASM?

Sorry, Jan does great work of course, but saying that “Jan is the only one that can make things work” because a program that already runs on SWI now also runs on SWI -wasm (which is the same) is partial at least… Different Prologs have different advantages, sometimes important ones. We are all currently very motivated to increase compatibility and portabiltiy (see the 50-years of Prolog TPLP paper that we have written together) and, honestly, a comment like this does not help the overall cause of Prolog, which is what should be our concern.

(Nothing of importance here)

I thought that the 24 hour limit was a joke. Seriously.

Back to subtract/3 or more in general the Prolog library. Most legacy systems have stuff that got there in the past for the wrong reason. SWI-Prolog subtract/3 is probably one of them. I think it got there through C-Prolog (may be wrong) :slight_smile: An identity rather than unification based implementation probably makes more sense.

I don’t see this as a very hard problem to resolve. As it makes little sense to use these predicates in situations where unification is intended the change will probable go unnoticed, as it did when list_to_set/2 changes from unification to identity somewhere in the past.

I think the route forward 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). That in itself probably provides incentive to fix many of these issues. Even if it doesn’t it would greatly help users writing portable code by avoiding these pitfalls.

3 posts were split to a new topic: Prolog PEP/RFC/…?

Looks like Ciao Prolog has a name clash/overriding again.
I find that one of their library is called sets and not ordsets. This
clashes with SICStus library for sets:

And the module name doesn’t comply with SWI-Prolog:

So a single source solution for Joseph Vidal-Rossets problem
of fCube would not work, if I would start importing a module library(sets).
Even if we would introduce it to SWI-Prolog. Single source solution

is, when I can freely copy paste between playgrounds.

That is not what I was referring too. I was referring to documentation pages such as on w3schools, e.g., JavaScript For Of. All these pages document browser support. So, for subtract/3 I would like to see a page documenting the two (or more) variations and the availability in Prolog systems that wish to contribute. Something like:

subtract(+Set, +Delete, -Result) is det.
bla bla.


  1. unification based bla bla
  2. identity based bla bla


SWI-Prolog: library(lists), variant (1)
Ciao: library(idlists), variant (2)

I.e., nothing technical, just docs. Ideally this would start discussion and cause systems to find a common ground. For example, I think id based is better. Surely if SWI-Prolog is the outlier I’m happy to change that, considering that the impact is most likely low.

I could figure out what you mean by Novacore.

This Novacore is very difficult. Even doing a Novecore which cannot
do Polyfills that would do mixin, but like could only consult different implementations. Is very hard. For example Ciao Prolog doesn’t

throw a singleton warning here:

/* Ciao Prolog 1.21.0 */
:- new_declaration(write/1).
:- write(X).

On the other hand, SWI-Prolog shows a singleton warning:

/* SWI-Prolog 8.5.14 */
:- write(X).

Warning: user://1:16:
Warning:    Singleton variables: [X]

Because there was no singleton warning, such single named variables
are even referenced then by Ciao Prolog in some comment like
addition to a kind of type declaration:

:- pred member(X,Xs) # "@var{X} is an element of (list) @var{Xs}.".

And these comments are even sometimes multiline, violating what
most Prolog systems exclude, since the ISO core standard has \ as
the continuation character for multiline quoted atoms.

I am still looking for the ultimate authorative references from the past. I find, with the comment:

%   File   : LISTUT.PL
%   Author : Bob Welham, Lawrence Byrd, and R.A.O'Keefe
%   Converted to NIP: K Johnson, 11.8.87
%   Updated: 12 February 1985
%   Purpose: list processing utilities

%   This module requires
%	listtoset/2	(from SetUtl.Pl) for remove_dups/2

So lets see whether there is a as well, and there you find:

%   File   : SETUTL.PL
%   Author : Lawrence Byrd + R.A.O'Keefe
%   Updated: 19 July 1984
%   Purpose: Set manipulation utilities

%	subtract/3,		%  Set x Set -> Set
%	listtoset/2,		%  List -> Set

Hope this helps!

Edit 18.08.2022
But then the old listtiset/2 had a different semantics again:

listtoset([], []).
listtoset([Head|Tail], Set) :-
	memberchk(Head, Tail), !,
	listtoset(Tail, Set).
listtoset([Head|Tail], [Head|Set]) :-
	listtoset(Tail, Set).

Here you see the difference:

?- list_to_set([c,a,b,a], X).
X = [c, a, b].

?- listtoset([c,a,b,a], X).
X = [c, b, a].

I still do not know what ‘Novacore’ means.

This is also funny, currently some more troubles with fCube:

/* SWI-Prolog 8.5.14 */
?- atom_concat('a', 123, X).
X = a123.

And then:

/* Ciao Prolog 1.21.0 */
?- atom_concat('a', 123, X).
{ERROR: No handle found for thrown exception 

A PEP could suggest atomic_concat/3, like Logtalk has,
and a non-legacy mode aka PEP mode of SWI-Prolog, where
atom_concat/3 is restored to a more limited behaviour?

Edit 25.08.2022
But maybe atomic_concat/3 is no good idea. Because
it suggests the availablity of other predicates, like
atomic_length/2. But the later doesn’t exist, and we have:

/* SWI-Prolog 8.5.14 */
?- atom_length(123, X).
X = 3.

And then:

/* Ciao Prolog 1.21.0 */
?- atom_length(123, X).
{ERROR: No handle found for thrown exception