After reading an old article in the Algol bulletin about questions
and issues with operator precedences I tried this with (Gnu) Awk
$ awk 'BEGIN { a=5; print a^2, -a^2, 0-a^2 }'
25 -25 -25
and shell (Ksh)
$ a=5 ; print $(( a**2 )) $(( -a**2 )) $(( 0-a**2 ))
25 25 -25
and Algol 68
$ a68g -p 'INT a=5; (a^2, -a^2, 0-a^2)'
+25 +25 -25
I don't want to value the different results (based on precedence),
but I'm interested in your comments/thoughts about the differences.
(expt 5 2)25
(expt 5 2 3)
(expt 5 2)25
(expt 5 2 3)390625
(expt (expt 5 2) 3)15625
(expt 5 (expt 2 3))390625
Furthermore exponentation between on an intermediate precedence level
between unary minus and regular minus is simply insane.
I made it n-ary in TXR Lisp:
(expt 5 2)25
(expt 5 2 3)390625
Kaz Kylheku <643-408-1753@kylheku.com> writes:
Furthermore exponentation between on an intermediate precedence level
between unary minus and regular minus is simply insane.
This is a very good argument! [...]
[...]
Moreover, what seams reasonable (to me) is that _unary_ operators
should (typically/always?) bind tighter than _binary_ operators!
This would imply that exponentiation does not bind higher than the
unary minus. (And that the order of the upthread posted Shell and
Algol 68 expressions would thus fit better.)
Kaz Kylheku <643-408-1753@kylheku.com> writes:
Furthermore exponentation between on an intermediate precedence level
between unary minus and regular minus is simply insane.
This is a very good argument! Prior to reading it I was kind of
indifferent (at least in infix programming languages, but not in typeset mathematics).
I made it n-ary in TXR Lisp:
(expt 5 2)25
(expt 5 2 3)390625
... so conforming to the habit of typeset mathematics, which is based on
the fact that
c
b
a
could be written as
bc
a
if meant to be left-associative. So having it right associative is the
more terse convention.
After pondering a bit more I think this is my personal resume...
On 24.05.2024 01:53, Janis Papanagnou wrote:
[...]
Moreover, what seams reasonable (to me) is that _unary_ operators
should (typically/always?) bind tighter than _binary_ operators!
An example may make things probably more apparent; in the expression
5 * -3 ^ 2
it would never occur to me to not consider the "-3" as an entity.
Because of the typical inherently tight coupling of unary operators.
(Assuming an interpretation of
5 * -(3 ^ 2)
would look just wrong to me.)
in the left associative semantics, we have a choice. We can do the exponentation earnestly as if by:
(expt (expt 5 2) 3)
Or we can take advantage of the identity:
(expt 5 (* 2 3))
The former could be important in some situation involving
floating-point: you can't always use simplifying identities.
I felt that the n-ary semantics of expt provided the best value
when right associative. It's not something obtainable by a ready
identity, and there is one obvious way to do it.
Now in the C grammar, we have multiplication also occuping a
precedence rung between unary plus/minus and additive expressions.
Thus -A*B means (-A)*B, whereas X - A*B means X-(A*B).
In this case it doesn't matter because the unary minus is
a kind of product. -A can be regarded as a shorthand for (-1)*A.
More importantly the identity (-A)*B = -(A*B) holds.
This creates a problem if we naively wedge exponentiation into
the grammar, by sticking it into a precedence level above
multiplication, but below unary.
The identity does not hold in exponentiation: (-A)**B
is not -(A**B).
It would be interesting to learn about the motivation for spreadsheets
and "bc" to deviate from the mathematical convention.
On 2024-05-24, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
After pondering a bit more I think this is my personal resume...
On 24.05.2024 01:53, Janis Papanagnou wrote:
[...]
Moreover, what seams reasonable (to me) is that _unary_ operators
should (typically/always?) bind tighter than _binary_ operators!
An example may make things probably more apparent; in the expression
5 * -3 ^ 2
it would never occur to me to not consider the "-3" as an entity.
Because of the typical inherently tight coupling of unary operators.
(Assuming an interpretation of
5 * -(3 ^ 2)
would look just wrong to me.)
That interpretation is required if - 3 ^ 2 is to correspond to:
2
-3
Indeed the ^ circumflex is intended to mean "we don't have support
for superscripts in this notation, but pretend that the 2 is raised up".
(In TeX/LaTeX, ^ is used for marking up superscripts: x^y.)
Now in the C grammar, we have multiplication also occuping a
precedence rung between unary plus/minus and additive expressions.
Thus -A*B means (-A)*B, whereas X - A*B means X-(A*B).
In this case it doesn't matter because the unary minus is
a kind of product. -A can be regarded as a shorthand for (-1)*A.
More importantly the identity (-A)*B = -(A*B) holds.
This creates a problem if we naively wedge exponentiation into
the grammar, by sticking it into a precedence level above
multiplication, but below unary.
The identity does not hold in exponentiation: (-A)**B
is not -(A**B).
On 25.05.2024 13:34, Axel Reichert wrote:
It would be interesting to learn about the motivation for spreadsheets
and "bc" to deviate from the mathematical convention.
It's not only these two program types. As noted upthread it's
also Ksh and Algol 68 (for example), and it seems quite common
in computing according to the cited Wikipedia article.
Kaz Kylheku <643-408-1753@kylheku.com> writes:
in the left associative semantics, we have a choice. We can do the
exponentation earnestly as if by:
(expt (expt 5 2) 3)
Or we can take advantage of the identity:
(expt 5 (* 2 3))
The former could be important in some situation involving
floating-point: you can't always use simplifying identities.
I cannot readily imagine a scenario in which simplifying is not possible
or is disadvantageous. Could you please elaborate?
(Mind my remark that mathematicians and computer scientists were
involved in the Algol 68 definition, and that this topic had been
discussed there, and despite the old mathematical convention they
decided to consistently streamline the definition. Frank Pagan's
Algol 68 book, for example says that _every_ monadic operator has
higher precedence than any dyadic operator. And that makes sense;
also in my opinion. I consider Algol 68 also a landmark due to its extraordinary formal definition, that's why I emphasize it here as
an outstanding paragon.)
This creates a problem if we naively wedge exponentiation into
the grammar, by sticking it into a precedence level above
multiplication, but below unary.
The identity does not hold in exponentiation: (-A)**B
is not -(A**B).
Looks like a non-sequitur to me.
People should be anyway aware of the operator precedences in the
various programming languages since there are obviously yet worse
definitions than the one we've been discussing here.
On 2024-05-25, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
People should be anyway aware of the operator precedences in the
various programming languages since there are obviously yet worse
definitions than the one we've been discussing here.
Which is why BSD has had an operator(7) man page about "C operator
precedence and order of evaluation" since 1990.
On 2024-05-25, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
(Mind my remark that mathematicians and computer scientists were
involved in the Algol 68 definition, and that this topic had been
discussed there, and despite the old mathematical convention they
decided to consistently streamline the definition. Frank Pagan's
Algol 68 book, for example says that _every_ monadic operator has
higher precedence than any dyadic operator. And that makes sense;
also in my opinion. I consider Algol 68 also a landmark due to its
extraordinary formal definition, that's why I emphasize it here as
an outstanding paragon.)
What they are effectively saying is that the dyadic power operator A**B
(or A^B or whatever it is) bears no syntactic relation to the 2D notation involving a superscript. I.e. it is a completely different syntactic interface to the same abstract operation. As such, it can have its own precedence rules, not hinged to the superscript power notation.
On 2024-05-25, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
People should be anyway aware of the operator precedences in the
various programming languages since there are obviously yet worse
definitions than the one we've been discussing here.
Which is why BSD has had an operator(7) man page about "C operator
precedence and order of evaluation" since 1990.
On 2024-05-26, Christian Weisgerber <naddy@mips.inka.de> wrote:
On 2024-05-25, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
People should be anyway aware of the operator precedences in the
various programming languages since there are obviously yet worse
definitions than the one we've been discussing here.
Which is why BSD has had an operator(7) man page about "C operator
precedence and order of evaluation" since 1990.
This discussion has convinced me that unary operators must not be
clumped together and put into a single precedence level.
For instance, if we have the C-like expression
-*p/*q
it should ideally be
-(*p/*q)
and not as it is now:
(-*p)/(*q)
due the unary minus being clumped with dereference.
Unary minus should not be a distinct operator from binary minus.
Unary minus should denote the elision of an identity element term,
so that - X not only means the same as 0 - X, but is considered
to be the same notation, just with the additive identity element not
show. We could correctly parse it as a binary minus by putting the
element back in.
This can make a difference easily. Consider that the unsigned types
in C have a definition for unary minus. If *p is of type unsigned
int, and its value is 1, then (-*p) is UINT_MAX. *q is 4 then
we get UINT_MAX / 4. Under the proposedd rule, we would get
something else: 1/4 producing 0, and that negating to 0.
Are you saying that the order
unary minus
exponentiation
binary minus
is somehow "wrong"?
People should be anyway aware of the operator precedences in the
various programming languages
There's three power operators in Algol 68 ('UP', '^', '**') each with
the same default precedence (and each individually changeable.
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
There's three power operators in Algol 68 ('UP', '^', '**') each with
the same default precedence (and each individually changeable.
As you have mentioned upthread, changing the precedence is scary.
Obfuscated Algol contest ... (-:
[...] It is the infix languages (which boast as an
advantage to be closer the usual mathematical notation) where I think it
is crucial to stay close to the mathematical notation, otherwise the purported advantage vanishes immediately.
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
Are you saying that the order
unary minus
exponentiation
binary minus
is somehow "wrong"?
It certainly feels like this to me. When thinking about the "why", I
could see two "arguments":
1. Unary and binary minus, while not identical operators, at least
visually are identical. Hence it reduces the cognitive load on the
reader of source code, who does not need to remember that unary minus
and binary minus are "on opposite sides of the 'exponentiation fence'".
2. Mathematical programming is algorithms (often beautifully typeset
with (La)TeX) transformed into more mundane ASCII-text representations
(which I see as a technical limitation). Using different operator
precedence depending on the visual representation is certainly confusing
if not dangerous (error-prone coding). Also, I do not see the benefit of deviating from the mathematical convention.
With the rather new trend to use UTF characters in source code (lambda
and other greek letter, arrows) the visual distinction between printed
math and written source gets smaller, so it makes less and less sense to
use different conventions for the two.
Best regards
Axel
On 30.05.2024 10:17, Axel Reichert wrote:
1. Unary and binary minus, while not identical operators, at least
visually are identical. Hence it reduces the cognitive load on the
reader of source code, who does not need to remember that unary minus
and binary minus are "on opposite sides of the 'exponentiation fence'".
I sort this "argument" (quotes borrowed from your text) into the same category as "[old] mathematical convention". IMO it doesn't withstand
the slightest analysis. To explain I'm going back to "Computer Science
101" as taught in the 1980's (and probably even before)...
You model expressions with Kantorovic trees (using a homonym '-' here)
a b c
\ / |
'-' '-'
but what I depicted are different operations, as can obviously be seen.
Their evaluation in a stack automaton will happen like
push(a); push(b); subtract() and push(c); negate() respectively.
If there wouldn't be a distinction and we had, say, a single 'minus()' operation there'd be no indication to reduce that part of expression.
Deviation from conventions makes sense when appropriate.
I'm glad that the "Burning Witches" convention has been superseded,
and that "Newton" got fixed by Relativity and Quantum Mechanics. :-)
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 1,030 |
Nodes: | 10 (0 / 10) |
Uptime: | 197:48:47 |
Calls: | 13,340 |
Calls today: | 3 |
Files: | 186,574 |
D/L today: |
2,726 files (836M bytes) |
Messages: | 3,356,969 |