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

Arbitrary Infix Operators #39355

Open
jonas-schulze opened this issue Jan 21, 2021 · 5 comments
Open

Arbitrary Infix Operators #39355

jonas-schulze opened this issue Jan 21, 2021 · 5 comments
Labels
feature Indicates new feature / enhancement requests parser Language parsing and surface syntax speculative Whether the change will be implemented is speculative

Comments

@jonas-schulze
Copy link
Contributor

Sometimes it's useful to have more verbose infix operators (e.g. isa). I would like to suggest adding a way to declare arbitrary identifiers <op> to be infix operators. Please consider the following syntax as a placeholder for the underlying idea.

@infix <precedence> <function> <op>
  • <precedence> would correspond to the currently existing lists prec-comparison, prec-plus, prec-times, etc. inside julia-parser.scm. Hence, allowed values should be predefined/limited.
  • <function> is the function to be executed.
  • <op> is the identifier of the new infix operator. This might be considered optional.

Example: Divisibility

@infix :comparison divides

divides(a, b) = b % a == 0

# Usage: `a divides b`

This syntax would also allow creating new infix operators from Unicode symbols, such that things like #39350 could just be done by a package. To simplify that workflow, it would be nice to define "tab completions" in a similar fashion.

@completion <ascii> <symbol>

Example: Independence (probability theory)

@infix :comparison indep 
@completion "indep" 

function indep(A, B) end

# Usage: `A \indep<TAB> B` or `A ⫫ B`

Extension to n-ary operators

The distinction between <function> and <op> allows this syntax to be extended to custom ternary operators.

@infix <precedence> <function> <op1> <op2> ...

Example: Conditional Independence

@infix :n_ary cond_indep  |

function cond_indep(A, B, C) end

# Potential usage: `A ⫫ B | C` or `@(A ⫫ B | C)`

The latter usage is currently invalid syntax.

Discussions concerning ternary operators (e.g. how to deal with precedence) might be better located in #39353.

@jonas-schulze jonas-schulze added parser Language parsing and surface syntax feature Indicates new feature / enhancement requests labels Jan 21, 2021
@mbauman
Copy link
Member

mbauman commented Jan 21, 2021

Somewhat related (albeit with a broader scope) is: #16985

This would be a very large change as it would no longer make parsing canonical. Parsing itself would become stateful — and that's something that I know Jeff is very reticent to do.

@mbauman mbauman added the speculative Whether the change will be implemented is speculative label Jan 21, 2021
@JeffBezanson
Copy link
Member

Just so; there is a lot of complexity here since not only does parsing become stateful but there are new scoping issues, i.e. there needs to be a way to import/export syntax from a package vs. keeping it local.

@jonas-schulze
Copy link
Contributor Author

there needs to be a way to import/export syntax from a package vs. keeping it local.

As it's already possible to use binary operators as identifiers,

julia> foo(_) = (_, _) -> true
cond_indep (generic function with 1 method)

julia> ⊕ = foo(42)
#1 (generic function with 1 method)

julia> 1 ⊕ 2
true

could this be handled the same as exporting functions?

module Foo

@infix :comparison compare comp 
compare(_, _) = 42

export compare       # only allows `compare(x, y)`
export comp          # only allows `x comp y`
export compare, comp # allows both

@infix :comparison _comp_
_comp_(_, _) = 21

export _comp_ # allows both `_comp_(x, y)` and `x _comp_ y`

end

@rben01
Copy link
Contributor

rben01 commented Dec 5, 2021

Rather than an @infix macro that turns a function into an infix operator, I think it'd be simpler to make @infix parse the current expression as infix, with every even-numbered top-level expression being treated as a function. So cmp(1, 2) could be written as @infix 1 cmp 2, and you could have e.g., @infix (1 + 2) (rand() < .5 ? cmp : +) (3 + 4), which would return -1 or 10. The @infix macro could also be placed before a begin ... end block to implicitly place @infix before every line.

The macro could also (somehow) take keyword arguments to convey the precedence and associativity of the infix-ed functions.

@KwatMDPhD
Copy link

Any progress on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Indicates new feature / enhancement requests parser Language parsing and surface syntax speculative Whether the change will be implemented is speculative
Projects
None yet
Development

No branches or pull requests

5 participants