Operator associativity

Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.29)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit https://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- op(100,xf,a).
true.

?- op(200,xf,b).
true.

?- display(a b a).
b(a(a))
true.

This is beyond my expectations. I think (a b a) was invalid. Logically b is a suffix operator, then (a b a) should be invalid.

2 Likes

This is indeed incorrect. Prolog operator handling is a bit of a mess. The ISO standard defines it precisely, but is far too restrictive. As a result even systems that care very much about the standard such as SICStus are more relaxed, often even more so than SWI-Prolog. I’m afraid it is not well defined what is accepted and what not, nor what parse you can rely on :frowning:

2 Likes

So now I’m curious. Does the definition of an operator preclude of override its use as an atom?

Considering (a b a) : the first a is clearly not a suffix so isn’t it just the atom a? The following b and a are suffix operators, so the question is, is the result b(a(a)) or a(b(a))? Since a has higher precedence, the current answer is at least plausible, but I’m not sure.

Replacing the first a with an arbitrary atom:

?- display(x a b).
b(a(x))
true.

?- display(x b a).
b(a(x))
true.

which would tend to support the interpretation above. If (x a b) is valid why wouldn’t (a b a) also be valid?

Now I don’t know what the standard says (never read it), but it doesn’t appear that the current situation is all that much of a mess. And it’s not obvious to me that the example should cause a syntax error of any kind.

2 Likes

The relevant part

Table 5 - Valid and invalid terms

Invalid term      Valid term
fx fx 1           fx (fx 1)
1 xf xf           (1 xf) xf
1 xfx 2 xfx 3     (1 xfx 2) xfx 3
1 xfx 2 xfx 3     1 xfx (2 xfx 3)

1 Like

Interesting. Any rationale why they thought cascaded suffix (or prefix) operators should be invalid?

Not that it matters a lot; as it says, you can always use parentheses to define it explicitly. Maybe they just wanted to avoid any confusion in semantics when the operators had different precedence, so just insist on the explicit form.

The standard uses the word rationale only twice and neither is related to operators.

The only line I find related to your question is

An operand with the same priority as a non-associative operator must be bracketed.

xf is a postfix not-associative operator.

I think this was the point I had forgotten (again). xfx, fx, and xf define non-associative operators so they can’t be “cascaded”. If I want to cascade a suffix, I should have to use associativity yf.

And I’m sure precedence is also an issue in cascading suffixes, i.e., (x a b) is legal given the specified precedences but (x b a) isn’t.

Looks like nobody respects these rules which is maybe why it’s a “mess”, although it’s not clear to me why it has to be that way.

2 Likes

I agree that this should always be true and is an excellent test case, independent of any operator issues. But I would also like to see a precise definition for what the semantics of op/3 should be so that users know (rather than guess) how to use it and implementations can be measured against it. If that’s available somewhere and I’ve missed it, can someone provide a link.

I also agree that one of the functions of the associativity parameter is to break ties when operators have the same precedence.

1 Like

The associativity modes xfx, yfx, etc… are less understandable than what was originally used?

Initially the directive was the predicate name AJOP with different argument order and mode icons:

See also:

The Birth of Prolog - Alain Colmerauer
https://web.stanford.edu/class/linguist289/p37-colmerauer.pdf

For those following along there is a recent related GitHub commit.

As b(a(x)) is really a wrong parse I had a closer look. Turns that there was a serious flaw in cascading postfix operators that nests the terms in the wrong order and hence does also not notice the priority conflict. Strange bug after all those years … I guess the message is that postfix operators are not popular :slight_smile:

The original example now raises a syntax error and cascading postfix operators produce the right term.

Thanks for reporting.

3 Likes

I hope no one took it as a feature or their codes won’t work anymore :rofl:

There seems to be a new bug.

This is my file t.pl (Click triangle to expand)
:-op(100,xf,xf100).
:-op(200,xf,xf200).
:-op(300,xf,xf300).
:-op(400,xf,xf400).
:-op(500,xf,xf500).
:-op(600,xf,xf600).
:-op(700,xf,xf700).
:-op(800,xf,xf800).
:-op(900,xf,xf900).
:-op(1000,xf,xf1000).
:-op(1100,xf,xf1100).
:-op(1200,xf,xf1200).

:-op(100,yf,yf100).
:-op(200,yf,yf200).
:-op(300,yf,yf300).
:-op(400,yf,yf400).
:-op(500,yf,yf500).
:-op(600,yf,yf600).
:-op(700,yf,yf700).
:-op(800,yf,yf800).
:-op(900,yf,yf900).
:-op(1000,yf,yf1000).
:-op(1100,yf,yf1100).
:-op(1200,yf,yf1200).

:-op(100,fx,fx100).
:-op(200,fx,fx200).
:-op(300,fx,fx300).
:-op(400,fx,fx400).
:-op(500,fx,fx500).
:-op(600,fx,fx600).
:-op(700,fx,fx700).
:-op(800,fx,fx800).
:-op(900,fx,fx900).
:-op(1000,fx,fx1000).
:-op(1100,fx,fx1100).
:-op(1200,fx,fx1200).

:-op(100,fy,fy100).
:-op(200,fy,fy200).
:-op(300,fy,fy300).
:-op(400,fy,fy400).
:-op(500,fy,fy500).
:-op(600,fy,fy600).
:-op(700,fy,fy700).
:-op(800,fy,fy800).
:-op(900,fy,fy900).
:-op(1000,fy,fy1000).
:-op(1100,fy,fy1100).
:-op(1200,fy,fy1200).

:-op(100,xfx,xfx100).
:-op(200,xfx,xfx200).
:-op(300,xfx,xfx300).
:-op(400,xfx,xfx400).
:-op(500,xfx,xfx500).
:-op(600,xfx,xfx600).
:-op(700,xfx,xfx700).
:-op(800,xfx,xfx800).
:-op(900,xfx,xfx900).
:-op(1000,xfx,xfx1000).
:-op(1100,xfx,xfx1100).
:-op(1200,xfx,xfx1200).

:-op(100,xfy,xfy100).
:-op(200,xfy,xfy200).
:-op(300,xfy,xfy300).
:-op(400,xfy,xfy400).
:-op(500,xfy,xfy500).
:-op(600,xfy,xfy600).
:-op(700,xfy,xfy700).
:-op(800,xfy,xfy800).
:-op(900,xfy,xfy900).
:-op(1000,xfy,xfy1000).
:-op(1100,xfy,xfy1100).
:-op(1200,xfy,xfy1200).

:-op(100,yfx,yfx100).
:-op(200,yfx,yfx200).
:-op(300,yfx,yfx300).
:-op(400,yfx,yfx400).
:-op(500,yfx,yfx500).
:-op(600,yfx,yfx600).
:-op(700,yfx,yfx700).
:-op(800,yfx,yfx800).
:-op(900,yfx,yfx900).
:-op(1000,yfx,yfx1000).
:-op(1100,yfx,yfx1100).
:-op(1200,yfx,yfx1200).
SWI-Prolog version 8.4.1 
?- display(fx100 1 xf200).
xf200(fx100(1))

SWI-Prolog version 8.5.4-47-g7937a1265
?- display(fx100 1 xf200).
ERROR: Syntax error: Operator priority clash
1 Like

Thanks. Pushed a fix.

1 Like

Wow!

Look what happened to your test file.


EDIT

You are were even mentioned in the latest release notes.

  • Fixes to read/1 and friends for postfix operators (@keke)
1 Like