Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add syntax for implicit coefficients #707

Closed
evhub opened this issue Dec 25, 2022 · 8 comments
Closed

Add syntax for implicit coefficients #707

evhub opened this issue Dec 25, 2022 · 8 comments

Comments

@evhub
Copy link
Owner

evhub commented Dec 25, 2022

Should compile

5 x**2 + 2 x

to

5 * x**2 + 2 * x

The biggest problem, unfortunately, is that this would have a different precedence than implicit function application f x currently has, since

a x**2 + b x

is currently valid and compiles to

a(x)**2 + b(x)

Probably, the best way to do this is to change the precedence of implicit function application to be just tighter than */@ and have implicit function application check if the function is an int/float/numpy dtype and in that case use multiplication rather than function application. However, this would be a breaking change.

@evhub evhub added the feature label Dec 25, 2022
@evhub
Copy link
Owner Author

evhub commented Dec 26, 2022

Current operator precedence table:

====================== ==========================
Symbol(s)              Associativity
====================== ==========================
f x                    n/a
await x                n/a
..                     n/a
**                     right
+, -, ~                unary
*, /, //, %, @         left
+, -                   left
<<, >>                 left
&                      left
^                      left
|                      left
::                     n/a (lazy)
a `b` c,               left (captures lambda)
  all custom operators
??                     left (short-circuits)
..>, <.., ..*>, <*..,  n/a (captures lambda)
  ..**>, <**..
|>, <|, |*>, <*|,      left (captures lambda)
  |**>, <**|
==, !=, <, >,
  <=, >=,
  in, not in,
  is, is not           n/a
not                    unary
and                    left (short-circuits)
or                     left (short-circuits)
x if c else y,         ternary left (short-circuits)
  if c then x else y
->                     right
====================== ==========================

New operator precedence table after this change:

====================== ==========================
Symbol(s)              Associativity
====================== ==========================
await x                n/a
**                     right
f x                    n/a
+, -, ~                unary
..                     n/a
*, /, //, %, @         left
+, -                   left
<<, >>                 left
&                      left
^                      left
|                      left
::                     n/a (lazy)
a `b` c,               left (captures lambda)
  all custom operators
??                     left (short-circuits)
..>, <.., ..*>, <*..,  n/a (captures lambda)
  ..**>, <**..
|>, <|, |*>, <*|,      left (captures lambda)
  |**>, <**|
==, !=, <, >,
  <=, >=,
  in, not in,
  is, is not           n/a
not                    unary
and                    left (short-circuits)
or                     left (short-circuits)
x if c else y,         ternary left (short-circuits)
  if c then x else y
->                     right
====================== ==========================

@evhub
Copy link
Owner Author

evhub commented Dec 26, 2022

If we do this, we should probably add a warning if we detect

f x ** y

since it'll change meaning from f(x)**y to f(x**y).

@evhub evhub added this to the v3.0.0 milestone Dec 27, 2022
@evhub
Copy link
Owner Author

evhub commented Jan 7, 2023

Problem—what are we supposed to do with this:

f a b ** +c d

Presumably it should go to:

f(a, b ** +c, d)

Also, what about:

a ** b c

Presumably that's a parse error?

@evhub
Copy link
Owner Author

evhub commented Jan 7, 2023

While we're at it, maybe we should also substantially decrease the precedence of .., since right now it's totally useless to have it higher than all the arithmetic operators, since we know they'll always result in an error when called on a function composition. Thus, new proposed precedence table is:

====================== ==========================
Symbol(s)              Associativity
====================== ==========================
await x                n/a
**                     right
f x                    n/a
+, -, ~                unary
*, /, //, %, @         left
+, -                   left
<<, >>                 left
&                      left
^                      left
|                      left
::                     n/a (lazy)
..                     n/a
a `b` c,               left (captures lambda)
  all custom operators
??                     left (short-circuits)
..>, <.., ..*>, <*..,  n/a (captures lambda)
  ..**>, <**..
|>, <|, |*>, <*|,      left (captures lambda)
  |**>, <**|
==, !=, <, >,
  <=, >=,
  in, not in,
  is, is not           n/a
not                    unary
and                    left (short-circuits)
or                     left (short-circuits)
x if c else y,         ternary left (short-circuits)
  if c then x else y
->                     right
====================== ==========================

With the rationale for it below :: being so that a :: b .. c raises an error immediately rather than lazily.

evhub added a commit that referenced this issue Jan 7, 2023
@evhub
Copy link
Owner Author

evhub commented Jan 7, 2023

Only thing left to do here now is add a warning to catch syntax with a new meaning.

@evhub evhub added resolved and removed resolved labels Jan 9, 2023
@evhub
Copy link
Owner Author

evhub commented Jan 9, 2023

Though it is technically syntactically valid Python, since it's never not a TypeError, we can also allow

5 (x + y)

here if we want.

Actually, this is a bad idea, because it encourages a (x + y), which will fail since that will turn into a function call.

@evhub evhub added the resolved label Jan 9, 2023
evhub added a commit that referenced this issue Jan 9, 2023
@evhub evhub closed this as completed Jan 9, 2023
@munael
Copy link

munael commented Jan 9, 2023

Julia has for constants only, IIRC.
So 2x^2 + 4x - 3 looks nice.
But you don't need to parse a x^2 + b x + c, not even mentally.
Even if Julia is in fact not like this, it might be a happy medium worth considering.

@evhub
Copy link
Owner Author

evhub commented Jan 9, 2023

@munael The problem with that is that b x is already valid Coconut (it compiles to b(x)). So if we were to add 5 x, but keep b x as b(x), we would still have to parse both, but they would be inconsistent with each other, with one giving you function application and the other giving you multiplication.

@evhub evhub mentioned this issue May 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants