Atom_split/3 is not defined?

I’m using: SWI-Prolog version 8.0.2.

When I try to use atom_split/3 I get the following error:

5 ?- atom_split(big_dog_tom, '_', X).
ERROR: Undefined procedure: atom_split/3 (DWIM could not correct goal)

I don’t see a library reference on the docs page:

https://www.swi-prolog.org/pldoc/doc_for?object=ifprolog%3Aatom_split/3

Where can I find this useful predicate?

1 Like

atom_split/3 is in a compatibility package as you note and is probably not what you really want.

However in standard SWI-Prolog is

atomic_list_conca(+List, +Separator, -Atom)

Creates an atom just like atomic_list_concat/2, but inserts Separator between each pair of inputs. For example:

?- atomic_list_concat([gnu, gnat], ', ', A). 
A = 'gnu, gnat'

The SWI-Prolog version of this predicate can also be used to split atoms by instantiating Separator and Atom as shown below.

?- atomic_list_concat(L, -, 'gnu-gnat').
L = [gnu, gnat]

In your case:

?- atomic_list_concat(L,'_',big_dog_tom).
L = [big, dog, tom].

For others reading this, _ is a variable and can cause problems here while '_' is an atom e.g.

?- atomic_list_concat(L,_,big_dog_tom).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:    [8] atomic_list_concat(_7338,_7340,big_dog_tom)
ERROR:    [7] <user>
1 Like

Do you have a similar replacement for at_split/3?:

https://www.swi-prolog.org/pldoc/doc_for?object=hprolog%3Asplit_at/4

See source

1 Like

See: pakage list_util (docs)

Also see: Package install errors - How to resolve after SWI-Prolog changed to using HTTPS

example:

?- list_util:split_at(2,[a,b,c,d,e],Prefix,Suffix).
Prefix = [a, b],
Suffix = [c, d, e].
1 Like

You don’t need github for that :slight_smile:

21 ?- listing( atomic_list_concat/3).
%   Foreign: system:atomic_list_concat/3

true.

22 ?- use_module(library(dialect/ifprolog)).
true.

23 ?- listing(atom_split/3).
ifprolog:atom_split(Atom, Delimiter, Subatoms) :-
    atomic_list_concat(Subatoms, Delimiter, Atom).

true.

Getting O(n^2) is not needed if you use a code list as intermediate. You might need a high N to win using code lists though.

Could be that you are talking about something else? It is not so high, try this:

?- length(L,10), maplist(=(abc),L), atomic_list_concat(L,',',R).
L = [abc, abc, abc, abc, abc, abc, abc, abc, abc|...],
R = 'abc,abc,abc,abc,abc,abc,abc,abc,abc,abc'.

Now do some measurement, absolutely it pays off already after N=2:

?- between(1,3,N), length(L,N), maplist(=(abc),L), 
time((between(1,100000,_), atomic_list_concat(L,',',_), fail; true)), fail; true.
% 200,000 inferences, 0.031 CPU in 0.031 seconds (101% CPU, 6400000 Lips)
% 200,000 inferences, 0.016 CPU in 0.022 seconds (70% CPU, 12800000 Lips)
% 200,000 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 6400000 Lips)
true.

?- between(1,3,N), length(L,N), maplist(=(abc),L), 
time((between(1,100000,_), atom_list_concat(L,',',_), fail; true)), fail; true.
% 300,000 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
% 600,000 inferences, 0.047 CPU in 0.053 seconds (88% CPU, 12800000 Lips)
% 900,000 inferences, 0.109 CPU in 0.100 seconds (109% CPU, 8228571 Lips)
true.

Below is the naive atom_list_concat/3 with O(N^2) atom_list_concat/3 complexity,
because N times O(N) complex of a naive atom_concat/3. You might get lower
complexity if atom_concat/3 uses some tricks, like Ropes, etc… or special help via

realloc() that avoids too much copying if not necessary, but the later would
also require identifying an atom accumulator by the Prolog compiler. Not sure
whether SWI-Prolog or some other Prolog system implements/uses that?

% atom_list_concat(+List, +Atom, -Atom)
atom_list_concat([X|L], D, A) :-
   atom_list_concat(L, X, D, A).

% atom_list_concat(+List, +Atom, +Atom, -Atom)
atom_list_concat([], A, _, A).
atom_list_concat([X|L], Y, D, A) :-
   atom_concat(Y, D, Z),
   atom_concat(Z, X, T),
   atom_list_concat(L, T, D, A).

Edit 17.04.2022:
There are different approaches to get non-naive atom_split(-,+,+) that is O(N). Most of
the algorithms avoid the unnecessary copying in naive atom_concat/3. There is one
algorithm which goes two pass through the list of atoms and precomputes the

resulting atom length and then allocates a string, which it then populates. Another
algorithm is one pass and it uses a buffer which has amortizised low complexity
concering the extension of this buffer. I think SWI-Prolog uses the one pass

approach, but I don’t know exactly what kind of buffer it is. I have realized a kind
of two pass approach for Dogelog Player and prototyped a little bit the use of
atom_split/3 for all kind of stuff. It has native support by JavaScript and Python.

And since yesterday I have the one pass approach in formerly Jekejeke Prolog.
Maybe you don’t need this all if you have some non-naive atom_concat/3. But
I even banned atom_concat/3. You can bootstrap it, in the mode (+,+,-) as follows:

atom_concat(X, Y, Z) :-
    atom_split(Z, '', [X,Y]).