Careful with subtract/3

: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