How does MakeBoxes handle an n-ary operator?
You were almost there. You just need to use the multiple-argument pattern, and generalize your code accordingly to create the internals of RowBox
programmatically:
xO /: MakeBoxes[xO[x___], form_] :=
RowBox[
Riffle[
Map[MakeBoxes[#, form] &, {x}],
"\[Union]"
]
]
Note however that the above implementation leaks evaluation. It may or may not be a problem, but for example here:
x = 1;
xO[x == 1, x > 1, x < 1]
one may argue that the desired result should not be sensitive to the possible global values that x
may have, so the result:
(* True \[Union] False \[Union] False *)
may be unsatisfacory. Thus, here is a more careful version:
ClearAll[xO];
SetAttributes[xO, HoldAllComplete];
xO /: MakeBoxes[xO[x___], form_] :=
RowBox@Riffle[
List @@ Replace[
HoldComplete[x],
elem_ :> With[{eval = MakeBoxes[elem, form]}, eval /; True],
{1}
],
"\[Union]"
]
which now gives
xO[x == 1, x > 1, x < 1]
(* x == 1 \[Union] x > 1 \[Union] x < 1 *)
You could make use of the internal typesetting function BoxForm`MakeInfixForm
for this purpose:
xO /: MakeBoxes[xO[a__], form_] := RowBox[BoxForm`MakeInfixForm[Or[a], "\[Union]", form]]
The key feature is that parenthesization of the arguments is controlled by the precedence of the head of the first argument, in this case Or
. Then:
xO[x == 1, x > 1, x < 1]
x == 1 \[Union] x > 1 \[Union] x < 1
If you want parenthesization of the arguments to be based on the precedence of Times
instead of Or
, you would do:
xO /: MakeBoxes[xO[a__], form_] := RowBox[BoxForm`MakeInfixForm[Times[a], "\[Union]", form]]
xO[x == 1, x > 1, x < 1]
(x == 1) \[Union] (x > 1) \[Union] (x < 1)