Visual presentation of (is) in SWISH

Hi,

A simple example with lists that found its way into a student exercise
results in different formatting in SWISH to other Prologs that the students use:

SWISH capture

I answered their questions about this by just saying it was a visual convention
to indicate that ‘is’ sometimes has special meaning… Was wondering what the precise
explanation would be, but I couldn’t find in the manual (maybe I just wasn’t looking
in the right places…) I hope the good and knowledgeable folk here might
share any insights.

Thanks much!

2 Likes

More precisely, is is an “operator”. Other operators include +, :-, and , (yes, comma as an operator is confusing because it’s not an operator when it’s separating arguments in a term).

The operators are defined with priorities. So, you can write a+b*c and it’ll be interpreted as a+(b+c). It also has a canonical representation: +(a,*(b,c)). You can see this by:

?- X = a + (b * c), write_canonical(X).
+(a,*(b,c))  % this is output from write_canonical
X = a+b*c.   % this is normal output, using the operator definitions

If you want to show that something isn’t an operator, you can put it in quotes or surround it with parentheses:

?- X = (is) +  b * 'is', write_canonical(X).
+(is,*(b,is))
X =  (is)+b*(is).

One thing that often confuses beginners is that “=” doesn’t evaluate anything; it merely says that two items unify. If you want to evaluate an arithmetic expression, you use is:

?- X = 1 + 2 * 3.
X = 1+2*3.

?- X is 1 + 2 * 3.
X = 7.

?- Y = 1 + 2 * 3, X is Y.
Y = 1+2*3,
X = 7.

For more on this, see the section in the manual on operators and also the documentation of is/2.

2 Likes

Something that throws me off sometimes is a discrepancy between how things are printed and what they are, e.g.

?- X = (is), writeln(X).
is
X =  (is).

Or

?- X = (a,b,c), writeln(X).
a,b,c
X =  (a, b, c).

Not sure why parentheses are removed…

1 Like

write/1 and friends also remove quotes. If you want the quotes, use writeq/1 or format/1 with ~q:

?- X = is, Y='FOO', format('~w ~q    ~w ~q~n', [X, X, Y, Y]).
is is    FOO 'FOO'
X =  (is),
Y = 'FOO'.

As to why there’s X = (is) instead of X = is … probably a bug, but benign. It’s surprisingly tricky to get the output exactly minimal. See also write_canonical/1. And if you want to define your own style, see print/1 – but I prefer to use that only for debugging.

2 Likes

Many thanks for the follow! I suppose that at some point I may have come across
write_canonical/1 but I had surely forgotten about it…

I think I got the sentence I needed from the operators manual page you supplied:

“Note that the portable way to stop an atom acting as an operator is to enclose it in parentheses like this: (myop).”

I was not aware of this before… I don’t think I’ve encountered it in the course of using other Prologs.

BTW, since I was looking at the is/2 manual page, I was wondering about the specification as
-Number is +Expr. I know that the advice is to use in this way, as the numerical result of evaluating
Expr is matched to the left, but the examples on the page have Number instantiated, so a mode of
?Number is +Expr reflects the implementation. Or, the manual is “prescriptive” in its descriptions?

Thanks again.

Yes, it was this appearance of (is) in SWISH output that was unusual to me, compared to other Prologs.
Still, I picked up good leads from the answers here. Thanks much.

See the instantion patterns section of Type, mode and determinism declaration headers.

- Argument is an output argument. It may be unbound at call-time, or it may be bound to a term. In the latter case, the predicate behaves as if the argument was unbound, and then unified with that term after the goal succeeds.

I see… The possibilities are significantly more nuanced than the +/-/? that I’m used to. I had to go looking for a definition of a “partial term”. This from the Glossary of the manual was interesting ^^

  • Partial term / Partially ground term: That term that is an unbound variable or may contain unbound variables not 100%% sure whether an unbound variable actually counts as such; the mode indicator descriptions seem to imply no).

Thanks. I’ll have a look at print/1.

No. That is not a bug. ISO demands that an atom that is defined as an operator and appears as an operant (of an operator) must be embraced. SWI-Prolog (and several others, like SICStus) do not enforce this while reading. So, x = is is valid input for SWI-Prolog, but e.g., GNU Prolog considers it a syntax error. SWI-Prolog term writing tries to emit a term in standard compliant format. Tries, as this is really hard. There is a crazy number of corner cases for serializing a term :frowning:

It is also wrong. Just updated SWISH to fix that. An atom that is an operator and that appears as a list element or argument to a normal compound (f(a,b,…)) never needs to be embraced. SWISH does not use the built-in write_term/2. Instead, it re-implements the whole logic in Prolog to emit HTML output which provides highlighting, dynamic folding and unfolding and switching between horizontal and vertical layout.

Unfortunately, as said, writing a term correctly is hard and this second implementation does has its own bugs :frowning:

P.s. The current SWI-Prolog git, addresses this and some other details write_term/2. Hopefully I did not introduce new bugs … The tests still pass :slight_smile:

2 Likes

Thanks for the update: I confirmed on SWISH. The thread was interesting, and my students will be most impressed to know that their questions were heard by the creators of the platform.

1 Like