Decision diagram for the SWI-Prolog "pseudo-types"

Why pseudo-types? Because they are not really types! But that won’t stop us from drawing a decision tree:

(Large image!)

I’m a bit unsure about the dict with the functor C'dict'. Can use that functor to build a dict using ..=? (I haven tried pulling it out of term using ..= and using it when recomposing actually; I have tried to type it directly, which leads to failure).

Note the interesting feature of the query var(X), which is both a query on the syntax and on the computational state. IMHO it should really be called freshvar(X). The queries are about syntactic structure except for the ones in the number domain, which are about underlying representation, kind of.


EDIT by EricGT

To get a better view of the image, using your Internet browser: open link in new tab

For Chrome it is a context menu item: Right click - Open link in new tab.

3 Likes

Although incomplete in the implementation, the overall idea is that predicates that require text input accept all text representations and produce the documented type as output.

I’m not seeing this. I think I’m misunderstanding. Why can’t the atom table use Unicode for names? Internally all strings could be pointers into a block of memory for string storage and there’s no reason this couldn’t be Unicode. I use UTF-8 encoding and it works out fine. In a flat system with no modules a functor could be saved in memory like this:

struct wam_functor
{
  wam_val_t *symbol;
  uint8_t arity;
  uint8_t spying;
  wam_val_t *entrypoint;
};

here symbol is a pointer to strings storage, arity is obvious, spying is a flag for the debugger, and entrypoint is either a pointer to bytecode storage or to the clause store.

Then it wouldn’t be char_code/2 though wouldn’t it? Surely your problem is not one of pollution (since you support preallocation of the one character ASCII atoms) but one of dimensioning (since you think it too expensive to preallocate the one character Unicode atoms).

1 Like

I just tried these out in my system and I get L=6 and A=ri. Did you expect those results or not? You’ve got me worried I’ve implemented Unicode support incorrectly. You’ve got me doing this:

| ?- Emote = '\u1f631'.
Emote = 😱 ? 

I can maybe see there being a problem with having a length in characters as Unicode talks about code points (can a codepoint comprise several characters - graphically I mean?).

I’m not surprised it isn’t becuase the output I showed wasn’t from SWI Prolog. I wrote

I just tried these out in my system

And by “my system” I mean a Prolog system I built myself. See page 11 of this manual http://barrywatson.se/download/manual.pdf for my implementation of Unicode escape sequences.

Just to be clear. I’m making no claims about SWI Prolog.

This is also a funny test case:

?- atom_concat(X, Y, 'Zürich').
 X = '', Y = 'Zürich' ;
 X = 'Z', Y = ürich ;
 X = 'Zü', Y = rich Etc..

An often neglect atom functionality is searching backwards.
Think of Java which has String.indexOf() and String.lastIndexOf(),
for both search directions:

?- last_atom_concat(X, Y, 'Zürich').
 X = 'Zürich', Y = '' ;
 X = 'Züric', Y = h ;
 X = 'Züri', Y = ch Etc..

Searching backwards through a string can be both applied to UTF-8
and UTF-16, these codes allow backward scanning. A Prolog system
can provide further analogues like for example last_sub_atom/5
as analogue of sub_atom/5.

1 Like

Maybe putting atom/1 above atomic/1 could be also mis-
leading. Not only strings are atomic also atoms are atomic.

?- atomic('abc').
true.

?- atomic("abc").
true.

Actually I think for Prolog we have this identity: Right?

atomic(X) <=> \+ var(X), \+ compound(X).

So the box “In this branch always atomic(X)” happens
already one branch above, a little earlier. I think also
a blob is never a compound, making the identity also

true for the SWI-Prolog implementation specific blobs.
But interestingly strings are not blobs:

?- blob('abc', X).
X = text.

?- blob("abc", X).
false.
1 Like

The atomic part should look like this

  • atomic
    • number
      • float
      • rational
        • integer
          • code (character)
    • string
    • blob
      • atom
        • char (1-length atom)
      • special constants ([], dict functor)
      • encapsulated foreign resources
        • stream handle
        • thread handle
        • clause handle
        • … (many more)

Blobs global shared (between threads) objects and are subject to (atom) garbage collection. All the others live on the Prolog (global) stack and are thread-local and subject to traditional Prolog GC. As @dtonhofer says, several of these types have multiple implementation that one could consider sub types. These distinctions are fully transparent to the user, but knowing about them can have some value for minimizing resource usage and designing tests for transformations that cross these borders. In particular

  • integers come in three forms
    • Inlined (min/max_tagged_integer) integers use no (additional storage)
    • 64-bit signed integers use 64-bit + two guard words on the global stack
    • GMP integers for anything larger. This is a serialization of the GMP structure on the global stack, again with two guard words.
  • Atoms and strings come in two forms: those with all characters in the range 0…255 are represented as a char* array
  • The others are a wchar_t* array, USC-2 on Windows, UCS-4 on anything else.

char and code do not use any special implementation.

3 Likes

Now I have a feeling that SWI-Prolog
new rational numbers have a predicate
missing. Before SWI-Prolog new rational

numbers I could check for a proper ratio
via this test, assuming we know already
\+ var(X):

?- .., X = _ rdiv _.

Whats the replacement now? From common
lisp there is the distinction

Common Lisp the Language, 2nd Edition
The types integer and ratio are disjoint subtypes of rational.
2.15. Overlap, Inclusion, and Disjointness of Types

So I guess a new predicate ratio/1 could
be useful. So then the check would be:

?- .., ratio(X).

Maybe it could be bootstrapped as denominator(X)=1,
but having a test predicate could be more efficient.

It’s not open source. As you see floats can be given the precision you want. What you see is pi approximated as a 64 bits of precision. Here’s the same for 8 bits and 800 bits. See the documentation for eval/2 to see how it is encoded. All floating point operations are written in Prolog.

| ?- set_prolog_flag(floating_point_precision, 8).
% yes
| ?- write_canonical(3.14), nl.
'$float'(201,2,8)
% yes
| ?- set_prolog_flag(floating_point_precision, 800).
% yes
| ?- write_canonical(3.14), nl.
'$float'(5234391329810685605152683655716187370758635283017987905911062382234769231686841176144324277684170118233199979815845093750022709298483701588085234501079701586184698699918501428393516454440774009412237537666670982555627237209419022113563643740,2,800)

% yes

I don’t implement that predicate.

I’m not entirely against it. I’m also not very convinced we need it. You get this using rational(X), \+ integer(X) or rational(X), denominator(X) =\= 1. I surely agree this is a bit clumsy, but it works and I only do not see many cases where you would like to use this test. For short, I rather wait for somebody with a real problem for which this would significantly simplify the code. Adding more primitives is not free and primitives that are never used thus make the system worse rather than better.

1 Like

No, I implement my elementary functions using the closest precision that can be found in Computer Approximations by Hart et al. I implement special functions using those special functions.

If the numerators and denominators can be compared using </2, >/2 then I don’t think you want ratios as a subtype of rational, specialised like you have described. It can lead to problems.

What I’m saying is nobody so have ratios as a type where numerator and denominator are integers. Ratios are not the result of division.

It seems SWI-Prolog is your Mr. Nobody. Well a ratio is the
result of rdiv/2, which is a form of division. And in SWI-Prolog
there is also a flag to use (/)/2 for this form of division:

SWI-Prolog (threaded, 64 bits, version 8.1.29)

?- X is 3 rdiv 4.
X = 3r4. 

?- X is 3/4.
X = 0.75.

?- set_prolog_flag(prefer_rationals, true).
true.

?- X is 3/4.
X = 3r4. /* this is a ratio, result of division */

This is brand new stuff in SWI-Prolog. It was partially discussed in
this thread Proper rational numbers (prototype for testing) few
months ago. But it is quite likely that novel stuff is lesser known.

1 Like

That’s rationals, not ratio.

If these were ratios then that would be absurd. As rationals I suppose it is ok.

ps. I edited my previous post before I saw your answer. For everyone else, I asked for those results.

A ratio is not the result of division like a rational. The following results are rational numbers.


?- X is 3/4.
?- X is -3 / 4.
X = -3r4.

?- X is 3 / -4.
X = -3r4.

Equating rationals and ratios turns the above into a claim that the ratio of larger to smaller is equal to the ratio of smaller to larger. Clearly absurd. This is known as Arnauld’s paradox.

1 Like

I agree it is common, very common, but very wrong! Whilst both N and R have arithmos as the ancient Greeks would call it, they didn’t mix them nor should we. There is a difference between multitude ( N ) and magnitude ( R ).