Is there a Prolog name for atom/1 or stream/1 etc (SWI-Prolog)

Viewed 141

Just made a funny observation. SWI-Prolog allows other things than
atom as a functor in a compound. For example it allows me to do:

/* atom as functor */
?- Y =.. [foo, bar].
Y = foo(bar).

/* stream as functor */
?- current_input(X), Y =.. [X, bar].
X = <stream>(0000000069066420),
Y = <stream>(0000000069066420)(bar).

I wonder whether there is a name for what is allowed as a functor,
i.e atom or stream etc.. . The error message by SWI-Prolog doesn't
tell me what is the name, it says it expects an atom:

?- Y =.. [1, bar].
ERROR: Type error: `atom' expected, found `1' (an integer)

But as can be seen a stream etc.. , which is accepted, is not an atom:

?- current_input(X), atom(X).
false.

What is the umbrella type for what SWI-Prolog accepts as functor?
P.S. My guess why this is allowed: It is for example used for Dicts,
dicts are compounds with a special functor C'dict'.

Edit 10.09.2021:
I first thought its simple/1. But simple/1 is reserved
for atom or var, according to this answer:
What is the meaning of predicate "simple/1" in Prolog (SWI-Prolog)

2 Answers

In SWI-Prolog, blobs (binary large objects) are used to store arbitrary binary data, including atoms, images, and stream handles. Particularly, a blob represening a stream handle is a unique symbol which has no syntactical representation (although it is outputted as <stream>(hex-number)).

The built-in predicate blob/2 can be used to get the type of a blob:

?- X = foo, blob(X,Y).
X = foo,
Y = text.

?- current_input(X), blob(X,Y).
X = <stream>(0000000069057160),
Y = stream.

Thus, I think the type accepted as functor in SWI-Prolog is blob.

In Dogelog Runtime we recently introduced a new type tester called symbol/1. One can imagine that it is bootstrapped from blob/2 as follows:

symbol(X) :- blob(X, _).

Dogelog Runtime does also accept symbols as functors, similar like SWI-Prolog. This is used to inline disjunction and if-then-else, and could have further optimization use cases. Functors are not only restricted to atoms, they can be atoms or references:

/* Dogelog Runtime, 0.9.6 */
?- current_input(X), atom(X).
fail.

?- current_input(X), Y =.. [X, bar].
X = [object Object], Y = [object Object](bar).

But I am currently thinking about extending (=..)/2 even more. Namely to allow a compound as functor. What should a compound as functor do? Very simple:

/* Expected Result */
?- X =.. [foo(bar), baz].
X = foo(bar, baz)

So (=..)/2 would add the arguments to the given compound. This further extension of (=..)/2 doesn't need a new data type in the compound functor, but rather changes its behaviour.

It would have a couple of use cases:

  • Old Higher Order:
    Bootstrapping apply/2 would be as easy as:

    apply(X,L) :- G =.. [X|L], G.
    
  • New Higher Order:
    Bottstrapping call/n would be as easy as:

    call(X,Y) :- G =.. [X,Y], G.
    call(X,Y,Z) :- G =.. [X,Y,Z], G.
    call(X,Y,Z,T) :- G =.. [X,Y,Z,T], G.
    Etc..
    
  • DCG Expansion:
    Expanding a non-terminal by an input and output list would be only a matter of calling (=..)/2. Here is an example:

    ?- G =.. [np(X),I,O].
    G = np(X,I,O).
    
Related