Change Operator Precedence of --> operator

I am trying to use --> operator with highest precedence

Unprotect[LongRightArrow];
LongRightArrow[obj_,property_]:=obj[ToString[property]];
Protect[LongRightArrow];


With this I can do basic operations like accessing properties of an association

In:=  obj = <|"a" -> {2, 3}, "b" -> 5|>
Out:= <|"a" -> {2, 3}, "b" -> 5|>
In:=  obj⟶a
Out:= {2, 3}


However when I try to access elements of list in obj-->a Part takes higher precedence. Same applies for operator ^.

In:=  obj⟶a[[1]]
Out:= Missing["KeyAbsent", "a[[1]]"]
In:=  obj⟶a^2
Out:= Missing["KeyAbsent", "2 a"]

• LongRightArrow doesn't have any built in precedence, according to reference.wolfram.com/language/tutorial/OperatorInputForms.html. You might be able to use reference.wolfram.com/language/ref/PrecedenceForm.html Mar 21, 2017 at 12:37
• what should obj-->Part[a,1] do? Mar 21, 2017 at 12:50
• not should but I want to change precedence such that it returns 2, (without affect other operations) Mar 21, 2017 at 13:12
• Do you mean you want obj-->a[[1]] to be interpreted as Part[obj-->a,1] and not obj-->Part[a,1] ? Or do you actually want obj-->Part[a,1] to give 2? @george2079 I think if he is talking about precedence he means the first. Mar 21, 2017 at 13:22
• Yes I want the first one. Mar 21, 2017 at 13:29

How about overloading the LongRightArrow with a special rule for Part[...] as the second argument?

Unprotect[LongRightArrow];
SetAttributes[LongRightArrow, HoldRest]
LongRightArrow[obj_, property_] := obj[ToString[property]];
LongRightArrow[obj_, Part[property_, partspec__]] :=
Part[LongRightArrow[obj, property], partspec];
Protect[LongRightArrow];
obj = <|"a" -> {2, 3}, "b" -> 5|>
obj⟶a
obj⟶a[[1]]

<|"a" -> {2, 3}, "b" -> 5|>
{2, 3}
2


Chip Hurst was quicker than I to show the generalization

LongRightArrow[obj_, head_[f_, args__]] := head[LongRightArrow[obj, f], args]


So I'll just take one more step to handle unary postfix operators, such as ! (Factorial). Trivial by replacing args__ with args___:

LongRightArrow[obj_, head_[f_, args___]] := head[LongRightArrow[obj, f], args]


Now

obj⟶a!

{2, 6}


EDIT
Re the comment:

obj⟶a⟶b


is equivalent to

LongRightArrow[obj, a, b]


while the desired behavior is

LongRightArrow[LongRightArrow[obj, a], b]


Well, obviously, that's exactly what we should tell Mathematica, it can't guess that for us.

LongRightArrow[obj_, a_, b__] := LongRightArrow[LongRightArrow[obj, a], b]
obj⟶a⟶b⟶b⟶b⟶b⟶b

 (((((obj⟶a)⟶b)⟶b)⟶b)⟶b)⟶b

• But this is not generic what about operator^ ? Mar 21, 2017 at 13:56
• @Neel True. Replace Part with a named pattern. I'll add an example once back at the computer. Mar 21, 2017 at 14:05
• Thanks, This works fine. However what about obj-->x-->y ? Now it works only if I bracket (obj-->x)-->y Mar 30, 2017 at 10:46
• @NeelBasu what do you expect from that expression? Its FullForm is LongRightArrow[obj, a, b]; you never proposed a rule for that in the first place. Mar 30, 2017 at 11:30
• obj-->x-->y to be evaluated as (obj-->x)-->y Mar 30, 2017 at 13:04

You could give LongRightArrow a HoldRest attribute and manipulate the right hand side.

Perhaps something like:

SetAttributes[LongRightArrow, HoldRest]

LongRightArrow[obj_, f_] := obj[ToString[f]]


Test:

obj⟶a

{2, 3}

obj⟶a[[1]]

2

obj⟶a^2

{4, 9}

• Looks like my answer near-verbatim ;-) Mar 21, 2017 at 14:28
• @LLlAMnYP Ah, I didn't see your answer until now... Mar 21, 2017 at 14:33
• Well now we have somewhat complementary answers. +1 Mar 21, 2017 at 14:40

The precedence of LongRightArrow is predetermined as shown in the operator table. You can attempt to circumvent the problem as other answers show but these do not change the binding power of the operator itself.

As you can see from the table Part has especially high binding power. What you want therefore goes against the design of Mathematica in some way; one would expect obj⟶(a[[1]]) rather than (obj⟶a)[[1]].

If you want to supersede Part you might consider something with natively higher binding power though there aren't many choices; Overscript is one:

Overscript[obj_, property_] := obj[ToString[property]];


Now entered using Ctrl+7:

Manually parenthesizing i.e. actually writing (obj⟶a)[[1]] is another option:

(obj⟶a)[[1]]

2


Note: you do not need to Unprotect Overscript or LongRightArrow as these operators are intended for use.

• Good catch about the absence of a Protected attribute. +1 Mar 21, 2017 at 15:27

If you don't mind mucking with the internal file UnicodeCharacters.tr (make a copy first!) you can change the line:

0x27F6 ⟶ ($-->$ $&LongRightArrow;$ $\longrightarrow$) Infix   650 None    2   2


to:

0x27F6 ⟶ ($-->$ $&LongRightArrow;$ $\longrightarrow$) Infix   750 Left    2   2


and then close and relaunch Mathematica so that the changes take affect. Afterwards I get:

obj⟶a[[1]]


2

and:

obj⟶a^2


{4, 9}

Also, the grouping change means:

obj⟶a⟶b //Hold //FullForm


Hold[LongRightArrow[LongRightArrow[obj,a],b]]

gets parsed the way you want.

• This is a great bit of knowledge, and the only answer here that really gets to the heart of the matter! Thanks! Is there somewhere I could read about the internal structure of Mathematica? (I'm looking to do other syntax-affecting things as well, like introducing new tokens—though that might be more complicated.) Jun 21, 2020 at 22:28