11

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"]
Carl Woll
  • 130,679
  • 6
  • 243
  • 355
Neel Basu
  • 961
  • 6
  • 14
  • LongRightArrow doesn't have any built in precedence, according to http://reference.wolfram.com/language/tutorial/OperatorInputForms.html. You might be able to use http://reference.wolfram.com/language/ref/PrecedenceForm.html – evanb Mar 21 '17 at 12:37
  • 1
    what should obj-->Part[a,1] do? – george2079 Mar 21 '17 at 12:50
  • not should but I want to change precedence such that it returns 2, (without affect other operations) – Neel Basu Mar 21 '17 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. – rhermans Mar 21 '17 at 13:22
  • Yes I want the first one. – Neel Basu Mar 21 '17 at 13:29
  • However if there exists any other method that gives 2 from obj-->Part[a,1] without altering precedence, I would like to learn that too – Neel Basu Mar 21 '17 at 13:30
  • I've tried using Notation But that didn't work – Neel Basu Mar 21 '17 at 13:46
  • it seems you need to modify Part somehow, or do you want to map to the first argument of any function, obj-->f[x] -> f[obj-->x] – george2079 Mar 21 '17 at 14:05
  • Part is not the only problem, this happens with other operators also, ^ is one such example – Neel Basu Mar 21 '17 at 14:07

4 Answers4

10

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
LLlAMnYP
  • 11,486
  • 26
  • 65
8

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

Perhaps something like:

SetAttributes[LongRightArrow, HoldRest]

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

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

Test:

obj⟶a
{2, 3}
obj⟶a[[1]]
2
obj⟶a^2
{4, 9}
Greg Hurst
  • 35,921
  • 1
  • 90
  • 136
6

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:

enter image description here

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.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
5

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.

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
  • 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.) – thorimur Jun 21 '20 at 22:28