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 ⟂ to infix operator precedence #24404

Merged
merged 10 commits into from
Dec 21, 2017
Merged

Conversation

chakravala
Copy link
Contributor

@chakravala chakravala commented Oct 30, 2017

Hi, since I am using , as binary mathematical infix operators for a package, it would help if these were able to be used as infix. I'm not entirely sure if I added it into the right place.

The goal is to be able to do something like

julia> [1,2,3] ↗ [3,2,1]
ERROR: syntax: extra token "" after end of expression
Stacktrace:
 [1] macro expansion at ./REPL.jl:97 [inlined]
 [2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73

Please let me know if there is something additional that needs to be done to allow this.

@JeffBezanson
Copy link
Member

Out of curiosity, what do you use them for?

@chakravala
Copy link
Contributor Author

chakravala commented Oct 30, 2017

Out of curiosity, what do you use them for?

It's called the "over" and "under" operation for binary trees. Essentially, it combines 2 trees into 1, the over operation α ↗ β identifies the root of α with the leftmost leaf of β, while the under operation α ↖ β identifies the rightmost leaf of α with the root of β.

It's a fairly standard operation, sometimes / or \ are used, but that conflicts with matrices in Julia.

You can find more information in the references of my package Dendriform.jl

@fredrikekre
Copy link
Member

@JeffBezanson
Copy link
Member

JeffBezanson commented Oct 30, 2017

Note that arrows use the precedence of "implies" so e.g. x↗y==z would parse as x↗(y==z) with this change.

@ararslan ararslan added needs news A NEWS entry is required for this change needs tests Unit tests are required for this change parser Language parsing and surface syntax labels Oct 30, 2017
@chakravala
Copy link
Contributor Author

chakravala commented Oct 30, 2017

Note that arrows use the precedence of "implies" so e.g. x↗y==z would parse as x↗(y==z) with this change.

Thanks for clarifying, what needs to be done to avoid that? which of these lists should it be added to?

@JeffBezanson
Copy link
Member

JeffBezanson commented Oct 30, 2017

I'm really not sure what precedence it should have (#23224 (comment)). I see the Arithmetree paper doesn't use exactly these operators, so that doesn't offer much guidance. Do these arrows have any other mathematical uses that might hint at their precedence (e.g. are they multiply-like or power-like)? Otherwise I'd probably just keep them in the "arrow" precedence level, and recommend parentheses.

By the way, the READMEs for your julia packages are really nice!!

@chakravala
Copy link
Contributor Author

chakravala commented Oct 30, 2017

I'm really not sure what precedence it should have (#23224 (comment)). I see the Arithmetree paper doesn't use exactly these operators, so that doesn't offer much guidance.

In that paper the symbol for over and under is / and \. However, in the new paper I am writing I have replaced it with the arrow notation, since it's actually slightly more indicative of what the meaning of it is. Also, since I would like this operation to work on vectors, I can't use \ and / in julia for it, since that would conflict with matrix operations. So I decided to use the arrow notation for that operation, which I saw in another paper on arxiv.

The way it's used in my package and in the math, it should be treated more like something of a multiplication or addition symbol. probably it should not be in the arrow category, I would prefer it to take precedence over order relations like < and ==, but I'm not sure what category would be right

By the way, the READMEs for your julia packages are really nice!!

Thank you very much, it is still a work in progress and not completed (missing some clear documentations), but I'm gradually trying to make it exciting for visitors to explore and discover

@pabloferz
Copy link
Contributor

pabloferz commented Oct 31, 2017

Maybe you can use and , but those would need to be added as infix operators as well.

EDIT:
'⍁': Unicode U+2341 (category So: Symbol, other) (APL FUNCTIONAL SYMBOL QUAD SLASH)
'⍂': Unicode U+2342 (category So: Symbol, other) (APL FUNCTIONAL SYMBOL QUAD BACKSLASH)

EDIT 2:
That would require to add autocompletions for the symbols to be practical though, something like \APLslash and \APLbackslash.

@chakravala
Copy link
Contributor Author

chakravala commented Oct 31, 2017

@pabloferz Thanks for the suggestion, but I've already settled for these symbols in writing the paper months ago. Having them as infix operators in Julia is an after thought at this point.

After thinking it over and taking a look at the other precedence lists, I figured it might actually fit into the prec-power list the best, due to its upward motion, and that would probably also give it the right kind of precedence that it needs mathematically. It seems that the prec-arrow list is all horizontal arrows anyway, so it probably makes more sense to put it into the power category from that perspective as well, plus the prec-arrow list already has so many in it, lets give prec-power some more symbol options

@chakravala
Copy link
Contributor Author

Also, I'd like to ask what is the reasoning behind placing ⊣, ⊢ under the comparison group? Is there a specific need for that? In dendriform algebra for example, these operations would be analogous to addition, in fact the addition is the union of those two operations. Not that it needs to be changed, but if there is no particular reason for it being in the comparison group, could we consider moving it to plus?

@JeffBezanson
Copy link
Member

In computer science is usually a relation, which is probably why we parse it as a comparison. See https://en.wikipedia.org/wiki/Turnstile_(symbol). I think this is pretty standard, so I'd rather keep it there.

@chakravala
Copy link
Contributor Author

chakravala commented Oct 31, 2017

Alright, I see. That explains why those need parenthesis.

One final thing is in the future I intend to use ⊥, but it has not been added to any list yet, so I went with the plus list for now. If that is alright, and the slanted arrows are alright, then this is finished.

Extra Idea: instead of hard-coding these operators, what if Julia allowed users to define their own operators and their precedence using multiple dispatch? then one particular definition of an operator might have some kind of precedence or associativity, while a different defintion of it for another purpose would have a completely different precedence and associativity, but it's the same symbol. This would allow a great deal of flexibility, if it were possible, but would need type inference.

@JeffBezanson
Copy link
Member

to me represents a bottom element. I don't think it's an operator.

define their own operators and their precedence using multiple dispatch

That would require knowing types before code is even parsed, which is not really possible. There could be a separate mechanism for customizing parsing of operators within a certain file, but some people find that confusing, plus it makes it harder to print expressions or copy and paste code.

@chakravala
Copy link
Contributor Author

to me represents a bottom element. I don't think it's an operator.

You mean like minimum of a set? Where is that notation used? In my case, it is used to represent the middle sum operation in the tri-algebra (which generalizes the di-algebra from binary trees to any tree) You can find it's usage in the Arithmetree paper and other papers talking about tri-algebras.

@JeffBezanson
Copy link
Member

It's very commonly used in lattice theory and type theory (https://en.wikipedia.org/wiki/Up_tack).

@chakravala
Copy link
Contributor Author

Then there's probably not a good argument for making it an op, so I removed the commit for that. Are the slanted arrows okay then?

If mathematics is ever formalized into something like a programming language, I wonder if somebody will find a clever way of handling these symbols with so many different meanings.

Now I'm beginning to gain a greater appreciation for natural language math and how flexible it is, that flexibility is not easily reproduced in a formal language.

@chakravala
Copy link
Contributor Author

chakravala commented Oct 31, 2017

@JeffBezanson might this be possible: could we make the list of operator precedences mutable, so that packages could define their own operator precedences at run time? e.g.

set_op_prec(:⊥, :plus)

then Julia would throw an error or warning if two packages try to add the same operator to conflicting precedence levels. This would solve many of the issues associated with the static operator precedence

Then the Base Julia precedence lists would only include the essential operators used by Base. If this was implemented, then it would also be much more clear to users how the precedence system actually works, because they helped define it as they are implementing their packages

Please let me know if that is feasible, and if the changes in this PR ar okay as-is.

@Liso77
Copy link

Liso77 commented Oct 31, 2017

As wiki says: "perpendicular symbol (⟂, \perp in LaTeX, U+27C2 in Unicode) is a binary relation symbol"

julia> "⟂"=="⊥"  # \perp  \bot 
false

I am not sure if it brings nice solution to the problem. :-)

@chakravala
Copy link
Contributor Author

chakravala commented Nov 1, 2017

Yes, so the \perp symbol should probably work as an operator in Julia, leaving the \bot available as a function name.

Wouldn't it make sense for Julia to have a mutable operator precedence system though? This would make it much more useful as a formal specficiation language for pure mathematics, since any symbol could have so many different contexts and meanings.

And if you disagree, then why not explain?

@StefanKarpinski
Copy link
Member

What I disagree with is user-controlled operator precedence. That's definitely not going to happen.

@JeffBezanson
Copy link
Member

Custom operator precedence is definitely controversial, but it should not be thought of as mutable operator precedence. In other words, you do not want an imperative command that says "change the precedence of operator x to y", but rather a scoped construct that says "in this file or block, operator x has precedence y". That would allow different packages to use different precedence rules simultaneously without interference.

However, that still has problems like that it's not possible to parse expressions without extra context info.

@JeffBezanson
Copy link
Member

\perp is a relation, so if we add it, it should go in the comparison precedence level.

@chakravala
Copy link
Contributor Author

In other words, you do not want an imperative command that says "change the precedence of operator x to y", but rather a scoped construct that says "in this file or block, operator x has precedence y". That would allow different packages to use different precedence rules simultaneously without interference.

This is actually what I meant as a feature. I didn't mean that the precedence should be fully mutable. What I meant is that it should be possible to add an operator precedence after Julia has started. After you set it, it should not be changed obviously, so it should not be mutable aftewards. What I meant in this case is that it should be possible to add to the list, but not necessarily undo it after the package has loaded already.

In this case, for most packages there would probably be a common system for defining the precedences. However, there might be the rare package that does not need to co-operate with other packages and would benefit from having completely different precedences.

Could you explain further what is the technical difficulty with it?

@chakravala
Copy link
Contributor Author

Hi, could we at least merge the perp symbol? The new commit only has it added, without the arrows.

@chakravala chakravala changed the title add ↗, ↖ as infix arrow operators add ⟂ to infix operator precedence Dec 15, 2017
@stevengj
Copy link
Member

@chakravala, you'll also have to remove from the list of allowed identifier characters in the parser.

Note that this is a breaking change and should be marked as such in the NEWS.

@stevengj stevengj added breaking This change will break code triage This should be discussed on a triage call and removed needs news A NEWS entry is required for this change labels Dec 15, 2017
@stevengj
Copy link
Member

stevengj commented Dec 15, 2017

Parsing as a comparison makes sense to me, since we already parse (U+2225) as a comparison operator too.

(If only weren't so microscopic in my font.)

@chakravala
Copy link
Contributor Author

Done. However, those are not the same symbol, I added the \perp symbol, which is different than the one in julia_extensions.c is. Hence, I did not remove it.

julia> ""==""
false

@chakravala chakravala changed the title add ⟂ to infix operator precedence add ⟂ and ∥ to infix operator precedence Dec 15, 2017
NEWS.md Outdated
@@ -31,7 +31,7 @@ New language features
`@generated` and normal implementations of part of a function. Surrounding code
will be common to both versions ([#23168]).

* Added `⟂` (perp) operator with comparison precedence ([#24404]).
* Added `⟂` (\perp) `∥` (\parallel) operator with comparison precedence ([#24404]).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is already in the list of comparison operators.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Sorry I initially led you astray on this.)

@stevengj
Copy link
Member

Would be good to add a test, e.g.

@test Base.operator_precedence(:) == Base.operator_precedence(:) == Base.operator_precedence(:<)

@stevengj
Copy link
Member

In julia_extensions.c, ⟂ (U+27c2) is included as an identifier char here, separate from U+27d8.

@chakravala chakravala changed the title add ⟂ and ∥ to infix operator precedence add ⟂ to infix operator precedence Dec 15, 2017
@chakravala
Copy link
Contributor Author

chakravala commented Dec 15, 2017

That is taken care of now. Thanks for checking it.

test/parse.jl Outdated
@@ -254,3 +254,6 @@ end
end
@test_throws ArgumentError parse(Complex{Int}, "3 + 4.2im")
end

# added ⟂ to operator precedence (#24404)
@test Base.operator_precedence(:∥) == Base.operator_precedence(:⟂) == Base.operator_precedence(:<)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly testing what the operator_precedence function returns seems kind of pointless since that's what you defined it to be. Testing the result of a few parses would seem to be a better end-to-end test.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like

@test Meta.parse("a ⟂ b ⟂ c") == Expr(:comparison, :a, :, :b, :, :c)
@test Meta.parse("a ⟂ b ∥ c") == Expr(:comparison, :a, :, :b, :, :c)

?

NEWS.md Outdated
@@ -31,6 +31,8 @@ New language features
`@generated` and normal implementations of part of a function. Surrounding code
will be common to both versions ([#23168]).

* Added `⟂` (\perp) operator with comparison precedence ([#24404]).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put backticks around \perp

@@ -84,7 +84,7 @@ static int is_wc_cat_id_start(uint32_t wc, utf8proc_category_t cat)

(wc >= 0x266f &&
(wc == 0x266f || wc == 0x27d8 || wc == 0x27d9 || // ♯, ⟘, ⟙
(wc >= 0x27c0 && wc <= 0x27c2) || // ⟀, ⟁, ⟂
(wc >= 0x27c0 && wc <= 0x27c2) || // ⟀, ⟁
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only changed the comment, not the code. Need to change the upper limit to 0x27c1.

@chakravala
Copy link
Contributor Author

fixed the test, news, and character range.

@JeffBezanson JeffBezanson merged commit bd04c13 into JuliaLang:master Dec 21, 2017
@JeffBezanson JeffBezanson removed the triage This should be discussed on a triage call label Dec 21, 2017
chakravala added a commit to chakravala/julia-vim that referenced this pull request Apr 19, 2019
carlobaldassi pushed a commit to JuliaEditorSupport/julia-vim that referenced this pull request Apr 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This change will break code needs tests Unit tests are required for this change parser Language parsing and surface syntax
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants