7

Suppose I have a simple function that I assign to an operator

f[a_, b_] := a + b
CirclePlus = f

Then I want to write

1 (+) 2 (+) 3

But it doesn't work, because it's trying to evaluate f[1,2,3].

So how does one instruct Mathematica that it should instead evaluate f[f[1,2],3], or alternatively how does one work with infix operators? I'd be okay if I had to write my as f[a_List] instead, and then took care of things myself ...

-- Edit:

As the answer was deleted, note that making the function Flat is not the answer, here, as far as I can see.

-- Edit:

Here is an exact copy of the MMA file to reproduce this problem

In[13]:= f[a_,b_]:=a+b;
f[a_,b_,c_]:=f[f[a,b],c]
CirclePlus=f;
1\[CirclePlus]2\[CirclePlus]5\[CirclePlus]6
Out[16]= f[1,2,5,6]
Noon Silk
  • 523
  • 3
  • 11

2 Answers2

10

You can tell it by making a definition what it should do if you have more then 2 arguments:

ClearAll[f];
f[a_, b_, c__] := f[f[a, b], c];
CirclePlus = f

Then you get

Mathematica graphics

And of course you have to add the definition of f when it is called as binary function. So for instance, and only for the purpose of showing what happens:

f[a_, b_] := Row[{"(", a, "\[CirclePlus]", b, ")"}]

Mathematica graphics

Here is how it looks when you use more than 3 terms. Note that the pattern is recursively applied until there are only 2 arguments in each call:

Mathematica graphics

halirutan
  • 112,764
  • 7
  • 263
  • 474
5

halirutan demonstrated how to adapt your function f to handle multiple arguments but that changes the game: f is no longer a binary function.

The other aspect of this problem is that the CirclePlus operator itself is not binary; rather it accepts a series of arguments as illustrated in the question. CircleMinus is a binary operator, and with it your code works as written:

f[a_, b_] := a + b
CircleMinus = f;

q ⊖ r ⊖ s ⊖ t
q + r + s + t

This of course would be a confusing choice of operator for this function but it serves as illustration. An additional property that must be considered is left versus right association. CircleMinus is left-associative:

CircleMinus = foo;

q ⊖ r ⊖ s ⊖ t
foo[foo[foo[q, r], s], t]

Therefore is right-associative:

Therefore = foo;

q ∴ r ∴ s ∴ t
foo[q, foo[r, foo[s, t]]]

Care should be exercised when choosing an operator for your function!

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • Well, in my case I'm actually performing a matrix direct sum, so I wanted the direct sum symbol. And that operation is associative. So how do I make CirclePlus be associative in the way I want? – Noon Silk Mar 22 '15 at 22:51
  • @NoonSilk Theoretically you could edit the entry for CirclePlus in UnicodeCharacters.tr following the format described here (6363) but I strongly recommend against it as your code will only work on a similarly modified system. I recommend that you choose a different existing operator, or possibly create a new one as also described in the post linked above. – Mr.Wizard Mar 23 '15 at 03:40
  • Yeah, I won't be editing that file. It seems crazy that I can't make this operator associative! – Noon Silk Mar 24 '15 at 21:46
  • @NoonSilk I believe it is a design choice, not necessarily one that I defend, but at least one I think I understand. The operator associativity is a low-level property that affects parsing itself. User definitions are applied after parsing. Therefore to affect this one must edit low-level properties, i.e. UnicodeCharacters.tr. Mathematica simply isn't designed to allow low-level modification of the syntax itself; even resource files such as UnicodeCharacters.tr are only limited exceptions to this. One would have to write his own parser to define a truly custom language syntax. – Mr.Wizard Mar 25 '15 at 05:36