# Operator associativity

**URL:** <https://swi-prolog.discourse.group/t/operator-associativity/4850>\
**Category:** Help!\
**Tags:** discussion\
**Created:** [January 6, 2022, 5:12pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850 "2022-01-06T17:12:11Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![keke](https://avatars.discourse-cdn.com/v4/letter/k/c5a1d2/32.png) [@keke](https://swi-prolog.discourse.group/u/keke)\
**Post date:** [January 6, 2022, 5:12pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/1 "2022-01-06T17:12:11Z")

</div>

```prolog
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.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 6, 2022, 6:55pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/2 "2022-01-06T18:55:29Z")

</div>

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 ☹

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [January 6, 2022, 8:51pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/3 "2022-01-06T20:51:39Z")

</div>

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:

```prolog
?- 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.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [January 6, 2022, 10:00pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/4 "2022-01-06T22:00:26Z")

</div>

> [@ridgeworks](#):
>
> what the standard says

The relevant part

```plaintext
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)

```

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [January 6, 2022, 10:25pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/5 "2022-01-06T22:25:55Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [January 6, 2022, 10:50pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/6 "2022-01-06T22:50:05Z")

</div>

> [@ridgeworks](#):
>
> Any rationale why they thought cascaded suffix (or prefix) operators should be invalid?

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.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [January 7, 2022, 3:22am UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/8 "2022-01-07T03:22:48Z")

</div>

> [@EricGT](#):
>
> `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`.

> [@anon95304481](#):
>
> You need to list also the operator priority,

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.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [January 7, 2022, 5:26pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/11 "2022-01-07T17:26:29Z")

</div>

> [@anon95304481](#):
>
> Usually one expects to have:
> 
> ```prolog
> x = parse(unparse(x))
> 
> ```

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.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [January 8, 2022, 9:00am UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/13 "2022-01-08T09:00:49Z")

</div>

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

> <https://github.com/SWI-Prolog/swipl-devel/commit/2c3197e970800d2fb54f1f3e82f34da36a2de965>

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 8, 2022, 3:31pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/14 "2022-01-08T15:31:42Z")

</div>

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 🙂

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

Thanks for reporting.

---

<div class="post-metadata">

**Author:** ![keke](https://avatars.discourse-cdn.com/v4/letter/k/c5a1d2/32.png) [@keke](https://swi-prolog.discourse.group/u/keke)\
**Post date:** [January 8, 2022, 3:58pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/15 "2022-01-08T15:58:55Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![keke](https://avatars.discourse-cdn.com/v4/letter/k/c5a1d2/32.png) [@keke](https://swi-prolog.discourse.group/u/keke)\
**Post date:** [January 9, 2022, 11:01am UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/16 "2022-01-09T11:01:15Z")

</div>

There seems to be a new bug.

> [@jan](#):
>
> postfix operators

> **This is my file t.pl (Click triangle to expand)**
>
> ```prolog
> :-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).
> 
> ```

```prolog
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

```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [January 9, 2022, 11:45am UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/17 "2022-01-09T11:45:41Z")

</div>

Thanks. Pushed a fix.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [January 9, 2022, 12:21pm UTC](https://swi-prolog.discourse.group/t/operator-associativity/4850/18 "2022-01-09T12:21:44Z")

</div>

Wow!

Look what happened to your test file.

> <https://github.com/SWI-Prolog/swipl-devel/commit/799ee52eaa78857e21e342a59b26da66fe1025b0>

* * *

**EDIT**

You are were even mentioned in the [latest release notes](https://swi-prolog.discourse.group/t/ann-swi-prolog-8-5-5/4861).

> - Fixes to [read/1](https://www.swi-prolog.org/pldoc/doc_for?object=read/1) and friends for postfix operators (@keke)
