15
$\begingroup$

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?

$\endgroup$
15
  • 3
    $\begingroup$ Unfortunately, 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. $\endgroup$ Jun 16, 2013 at 6:16
  • 2
    $\begingroup$ You 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? $\endgroup$
    – Rojo
    Jun 16, 2013 at 18:46
  • 3
    $\begingroup$ I 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. $\endgroup$
    – rcollyer
    Jun 18, 2013 at 15:49
  • 1
    $\begingroup$ it would be much simpler for you to use one of the several built-in infix operators that have no meaning (such as CirclePlus, CircleTimes...) $\endgroup$
    – rm -rf
    Jan 2, 2014 at 14:06
  • 1
    $\begingroup$ I found this post : mathematica.stackexchange.com/questions/6355/… $\endgroup$
    – tchronis
    Jan 2, 2014 at 14:39

3 Answers 3

20
$\begingroup$

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

enter image description here

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]

enter image description here

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["=", 
       AdjustmentBox["\[CirclePlus]",
         BoxBaselineShift -> -2.5,
         BoxMargins -> {{-0.7638888888888887, 
        0.7638888888888887}, {2.5, -2.5}}]],
   BoxFrame -> False, FrameMargins -> {{5, 0}, {0, 0}}]]
$\endgroup$
12
  • $\begingroup$ 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 :-) $\endgroup$
    – Mr.Wizard
    Jan 2, 2014 at 18:27
  • $\begingroup$ @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 $\endgroup$
    – Rojo
    Jan 2, 2014 at 18:30
  • $\begingroup$ @Rojo thank you very much. Could you add an example just for clarity? $\endgroup$
    – tchronis
    Jan 2, 2014 at 19:09
  • 1
    $\begingroup$ Nice, +1! Could you give a small snapshot? $\endgroup$
    – ybeltukov
    Jan 2, 2014 at 19:25
  • 1
    $\begingroup$ @Rojo I am very happy with this approach. Indeed any Infix operator can be generalized using subscripts for levelspec but not only. Thanks again. $\endgroup$
    – tchronis
    Jan 3, 2014 at 9:34
3
$\begingroup$

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 ==< *)
 CircleAddTo[x_List, y_] := AppendTo[x, y]

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

Use one new variable name z

 (*Input 6 ==< *)
 Clear[CircleAddTo]

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

 (*Input 8 ==< *)
 {CircleAddTo[a, 10], a}
(*
 Output==>
 {{1,2,3,4,10},{1,2,3,4}}
*)
 (*Input 9 ==< *)
 {CircleAddTo[a, 10], z}
(*
 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 ==< *)
 Interpretation["\[CirclePlus]=", CircleAddTo]; 

 (*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 ==< *)
 p = CircleAddTo; 

 (*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"]

enter image description here

 (*Input 19 ==< *)
 CircleAddTo[a, 6]
(*
 Output==>
 {1,2,3,4,6}
*)
$\endgroup$
2
$\begingroup$

No, unfortunately you cannot create a new compound operator such as ⊕= or @@@@, as stated by Michael Pilat in response to my own question of similar nature:

You can't do this with an operator syntax of your own invention (like @@&). Mathematica just doesn't have the capability to modify the language grammar at runtime like that.

There are a variety of methods you can use to effect new operators in the Front End but they are not actually extending the syntax of the language. Michael Pilat gives an example using the Notation Package in the referenced Q&A. More low-level you can modify the UnicodeCharacters.tr file as described in How is + as an infix operator associated with Plus? You could also use MakeBoxes, $PreRead, or CellEvaluationFunction, but again none of these will work in Packages, so you are better off using built-in operators that are undefined.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.