## Is it possible to define custom compound assignment operators like ⊕= similar to built-ins +=, *= etc?

15

9

I would like to do something like this:

In[1]:= ToExpression["\"\\[CirclePlus]\""]
Out[1]= ⊕

In[2]:= list_ ⊕ element_ := Append[list, element];

In[3]:= a = {1, 2};

In[4]:= {a = a ⊕ 3, a}
Out[4]= {{1, 2, 3}, {1, 2, 3}}

In[5]:= {a ⊕= 4, a}

(* Desired result: Out[5]= {{1, 2, 3, 4}, {1, 2, 3, 4}} *)
(* Actual result: syntax error *)

Syntax::sntxf: "a⊕" cannot be followed by "=4".

Is it possible to workaround this error and make the compound assignment operator ⊕= work?

Another example: I would like to create a new infix operator @@@@ (or other) to express Apply[f,expr,{2}] in a short form like f @@@@ expr. If precisely this is not possible what are the valid "names" I could use?

1it would be much simpler for you to use one of the several built-in infix operators that have no meaning (such as CirclePlus, CircleTimes...) – rm -rf – 2014-01-02T14:06:31.510

Thank you, you mean to define CirclePlus[f_, expr_] := Apply[f, expr, {2}]. Yes this solves my problem I saw in MMA's help there are CirclePlus, CircleMinus, CircleTimes and CircleDot. Also there are the OperatorsWithoutBuiltInMeanings that someone could use. Do you know If I could create my new one as a symbol combination ? – tchronis – 2014-01-02T14:30:41.867

1

– tchronis – 2014-01-02T14:39:48.357

Closely related: (9788)

– Mr.Wizard – 2014-08-08T18:38:53.660

Infact CirclePlus[x_List, y_] := Append[x, y] works. Then you can try things like "{1,2,3} \ [CirclePlus] 4". – Ali – 2013-06-16T05:13:57.520

I tried something along these lines: http://reference.wolfram.com/mathematica/tutorial/LowLevelInputAndOutputRules.html, but failed.

@Ali I would like to use operator that looks like ⊕= for the compound assignment. – Vladimir Reshetnikov – 2013-06-16T05:53:23.600

3Unfortunately, you cannot define new operators like this. You can have the operator itself, but not the sigil to represent it, as it seems that the parser is not user-programmable. If it were, the Notation package wouldn't be needed. – Oleksandr R. – 2013-06-16T06:16:05.097

@VladimirReshetnikov using my previous comment you should be able to write {1,2,3} ⊕ 4. About ⊕= I think it would be easier if you just define it as CirclePlus[x_List, y_] := AppendTo[x, y]. Good luck :) – Ali – 2013-06-16T14:15:24.290

2You can have it if you can live with using an input alias (esc + sth + esc) to input it. If you build your operator from other operators with sub-super-under-etcscripts, then it is more straighforward. Are you interested in any of these solutions? – Rojo – 2013-06-16T18:46:56.803

@Rojo Yes, I'm interested. – Vladimir Reshetnikov – 2013-06-16T21:00:42.400

I posted something. I wasn't pinged with your comment, don't know why – Rojo – 2013-06-18T15:41:07.633

3I would add one caution: \[CirclePlus], etc. are System symbols, and while they do not have any defined behavior (which makes them nice to overload), adding a definition will seemingly "break" the encapsulation of unique notebook or cell group contexts. The key is they're essentially global, so if you define them in one place, the definition is accessible without any qualifications. Yes, I've done this to myself. – rcollyer – 2013-06-18T15:49:13.480

@rcollyer This is good to know. Thanks! – Vladimir Reshetnikov – 2013-06-18T20:18:49.557

Honestly, it took me a few minutes to figure out why the notebook where I hadn't defined \[CircleTimes] was using the code from the notebook where I had. Since I run notebook unique contexts by default, I thought I stumbled upon a bug ... – rcollyer – 2013-06-18T20:43:30.403

20

You can use any built in operator modified with subscripts, superscripts, etc, and retain its precedence, for your own purposes. For example, say you want a general Apply operator like @@ that could work at any level. One could use create the operator @@ with a number subscripted for the level of Apply seems appropriate

MakeExpression[RowBox[{fun_, SubscriptBox["@@", i_], rhs_}], StandardForm] :=
MakeExpression[{fun, rhs, i}, StandardForm] /.
HoldComplete /@ {f_, r_, level_} :>
HoldComplete@Apply[f, r, {level}]

To use it, you just type your usual @@ followed by the subscript hotkey (ctrl+- for example) and then the level of application.

Example, run

Cell[BoxData@RowBox[{"f",
SubscriptBox["@@", "1"],
RowBox[{"Nest", "[",
RowBox[{"List", ",", " ", "0", ",", "6"}], "]"}]}],
"Input"] // CellPrint

This has limitations, of course. For your problem you could

MakeExpression[
RowBox[{lhs_, UnderoverscriptBox["+=", "_", "_"], rhs_}],
StandardForm] :=
MakeExpression[{lhs, rhs}, StandardForm] /.
HoldComplete /@ {f_, r_} :> HoldComplete@underlineAddTo[f, r]

or

MakeExpression[
RowBox[{b___, x_, UnderscriptBox["=", "\[CirclePlus]"], y_, a___}],
StandardForm] :=
MakeExpression[
RowBox[{b, RowBox[{"gplus", "[", RowBox[{x, ",", y}], "]"}], a}],
StandardForm]

As it is, your operator is an equal sign with an underscripted circle plus. However, some boxes are transparent for parsing, so you could define the following input alias for a different layout of the operator

PrependTo[CurrentValue[InputNotebook[], InputAliases],
"c+=" -> FrameBox[UnderscriptBox["=",
BoxBaselineShift -> -2.5,
BoxMargins -> {{-0.7638888888888887,
0.7638888888888887}, {2.5, -2.5}}]],
BoxFrame -> False, FrameMargins -> {{5, 0}, {0, 0}}]]

I like this a lot. I usually rely on the Notations package, but since I recently noted the overhead of that package I like the idea of a manual definition such as this. +1 :-)

– Mr.Wizard – 2014-01-02T18:27:05.517

@Mr.Wizard I don't understand the Notation package too much (my fault, I never devoted enough time to that). As soon as I have time I'll look at your liked question. It seems interesting – Rojo – 2014-01-02T18:30:57.933

@Rojo thank you very much. Could you add an example just for clarity? – tchronis – 2014-01-02T19:09:23.863

@tchronis, humm, I am not sure it will add clarity :P – Rojo – 2014-01-02T19:19:31.173

1Nice, +1! Could you give a small snapshot? – ybeltukov – 2014-01-02T19:25:11.533

I haven't posted an image since the image uploader broke and then I got lazy to get the fix. Could anyone post @ybeltukov's snapshot? – Rojo – 2014-01-02T19:29:35.570

@Rojo you don't need the uploader any more, just paste from clipboard works now on all SE sites. – Ajasja – 2014-01-02T19:33:32.023

@Ajasja, I wasn't able to copy paste :S – Rojo – 2014-01-02T19:38:21.067

Very Nice @Rojo , I am converging to accept your solution :-P. – tchronis – 2014-01-02T21:01:27.890

@Rojo Well, happy to be of service, since I was already in the neighborhood:) – Ajasja – 2014-01-02T22:39:59.810

1@Rojo I am very happy with this approach. Indeed any Infix operator can be generalized using subscripts for levelspec but not only. Thanks again. – tchronis – 2014-01-03T09:34:15.007

@Mr.Wizard I see I had already posted an answer there that wasn't very much appreciated probably saying the same thing. Feel free to merge, but I wouldn't press for an accept, and I'll delete that one – Rojo – 2014-08-08T18:14:13.777

3

This is my little test, and I encountered with some problems.

(*Input 1 ==< *)
(list_) \[CirclePlus] (element_) := Append[list, element];

(*Input 2 ==< *)
(x_List) \[CirclePlus] (y_) := Append[x, y]

Failed try.

(*Input 3 ==< *)

(*Input 4 ==< *)
(*
Output==>
AppendTo[{1,2,3},6]
*)
(*Input 5 ==< *)
a = {1, 2, 3, 4};

Use one new variable name z

(*Input 6 ==< *)

(*Input 7 ==< *)
CircleAddTo[x_List, y_] := (Clear[z]; z = Append[x, y])

(*Input 8 ==< *)
(*
Output==>
{{1,2,3,4,10},{1,2,3,4}}
*)
(*Input 9 ==< *)
(*
Output==>
{{1,2,3,4,10},{1,2,3,4,10}}
*)

one method use string symbol

Convert CircleAddTo to string symbol $\text{$\oplus $=}$

(*Input 10 ==< *)

(*Input 11 ==< *)
{a~"\[CirclePlus]="~7,z,a}
(*
Output==>
{{1,2,3,4,7},{1,2,3,4,7},{1,2,3,4}}
*)

Of couse,we could use one New Sybmol to replace the compound symbol $\oplus =$

(*Input 12 ==< *)
(a_) \[CircleTimes] (b_) := CircleAddTo[a, b]

(*Input 13 ==< *)
a \[CircleTimes] 9
(*
Output==>
{1,2,3,4,9}
*)
(*Input 14 ==< *)
{z, a}
(*
Output==>
{{1,2,3,4,9},{1,2,3,4}}
*)

or

(*Input 15 ==< *)

(*Input 16 ==< *)
{a~p~7, z, a}
(*
Output==>
{{1,2,3,4,7},{1,2,3,4,7},{1,2,3,4}}
*)

# NotationPackage

Notation/tutorial/NotationSymbolizeAndInfixNotation

(*Input 17 ==< *)
<< "Notation`"

(*Input 18 ==< *)
Cell[BoxData[RowBox[{"InfixNotation", "[", RowBox[{TemplateBox[{SubscriptBox["\[CirclePlus]", "="]},"NotationTemplateTag"], ",","CircleAddTo"}], "]"}]], "Input"]

(*Input 19 ==< *)