17
$\begingroup$

The default CellEvaluationFunction is Identity but one can quickly see that this is handled specially as an equivalent function, (# &), does not work at all the same. The sole example in the documentation uses ToExpression but this also does not work the same, returning only the output of the last line in the Input Cell:

SetOptions[EvaluationNotebook[], CellEvaluationFunction -> ToExpression]

Now in one cell:

2 + 2
5 + 7
12

My question is then: What is the real default function that correctly handles multi-line input/output including the Out[xx]= cell labels?

$\endgroup$
7
  • 2
    $\begingroup$ Could it be MakeExpression ? The docs say "MakeExpression is used whenever boxes are supplied as input to Mathematica." $\endgroup$ Commented Jul 27, 2013 at 8:49
  • $\begingroup$ @Simon That's a fine guess but it's not the whole story. If you try SetOptions[EvaluationNotebook[], CellEvaluationFunction -> Function[Null, MakeExpression[##], HoldAll]] you'll get ErrorBox for output. (Not that HoldAll should not be necessary for Box form but I'm covering that as well.) Once again there appears to be something funny going on here, where Identity and MakeExpression are handled specially. I'm trying to figure out how to change the Box form then send it to the true default function for correct processing. $\endgroup$
    – Mr.Wizard
    Commented Jul 27, 2013 at 11:44
  • $\begingroup$ Ah, I see. There does appear to be special handling. Even CellEvaluationFunction :> (Null; Identity) doesn't work. $\endgroup$ Commented Jul 27, 2013 at 18:16
  • 1
    $\begingroup$ Based on LinkSnooper it is based on MakeExpression. The FE sends EnterExpressionPacket@MakeExpression@BoxData[..]. I get errors like you do, if I do it myself, so it must be handled specially. $\endgroup$
    – Michael E2
    Commented Jul 30, 2013 at 20:28
  • $\begingroup$ It seems to me that what you're after will have to be done via MathLink packets. The In/Out names, for instance, are handled with InputNamePacket, OutputNamePacket. If you're lucky, a solution won't be version dependent. $\endgroup$
    – Michael E2
    Commented Jul 30, 2013 at 20:28

3 Answers 3

2
$\begingroup$

The documentations says that "CellEvaluationFunction is applied to the BoxData expression representing the input to be evaluated". So I think Identity is working normally here. See the followings:

SetOptions[EvaluationNotebook[], CellEvaluationFunction -> function]

In[1]:= 2 + 2
        5 + 7

Out[1]= function[BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}], StandardForm]

So, if we take the BoxData structure of the above input, we can do some tests:

Identity[BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}]]
(* BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}] *)

# &[BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}]]
(* BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}] *)

So, Identity sends the expression BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}] to the kernel and it produces the two lines of output with different Out[number] like

In[1]:= 2 + 2
        5 + 7

On the other hand, ToExpression is declared as working on strings and boxes interpreting them as inputs, that means if set as CellEvaluationFunction it manipulates the box structure before to send it to the kernel:

ToExpression[BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}]]

12 

So, I guess Identity is actually the CellEvaluationFunction's default. The only think I cannot understand is why when we set an arbitrary function (like in my first example) as CellEvaluationFunction, the result includes the StandardForm as second argument (function[BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}], StandardForm]) while Identity doesn't accept a second argument and, indeed, it's not used.

EDIT

Using (#&) it fails but using (#)& it works:

SetOptions[EvaluationNotebook[], CellEvaluationFunction -> (# &)]

In[78]:= 2 + 2

Out[78]= BoxData[RowBox[{"2", "+", "2"}]]

In[79]:= 2 + 2
5 + 7

Out[79]= BoxData[{RowBox[{"2", "+", "2"}], RowBox[{"5", "+", "7"}]}]


SetOptions[EvaluationNotebook[], CellEvaluationFunction -> (#) &]

In[74]:= 2 + 2

Out[74]= 4

In[75]:= 2 + 2
5 + 7

Out[75]= 4

Out[76]= 12
$\endgroup$
6
  • $\begingroup$ Bob, thanks for responding. I fear I haven't phrased this question adequately. I pointed out that using (# &) in place of Identity causes this to fail. The thing is I want to use CellEvaluationFunction to modify the Box data (like $PreRead), then send it along to the kernel as usual. So far everything I've tried has failed. Sure, I can get a kind of output and display it with CellPrint but it doesn't have the Out[xx]= labels and is a hack. $\endgroup$
    – Mr.Wizard
    Commented Jul 27, 2013 at 12:19
  • 1
    $\begingroup$ Regarding your update, I'm sorry to inform you that you're being fooled by evaluation order. If you use these methods you will see that the entirety of CellEvaluationFunction -> (#) & is the Function, which by itself is inert, therefore you are not making an Option setting at all. $\endgroup$
    – Mr.Wizard
    Commented Jul 27, 2013 at 13:46
  • $\begingroup$ You are right, I was indeed surprised of the difference. I'm still looking at some alternatives, to no avail. $\endgroup$
    – bobknight
    Commented Jul 27, 2013 at 13:58
  • $\begingroup$ @Mr.Wizard, the labels is just a matter of using CellLabel -> ($Line /. l_ :> ToString@Unevaluated@Out@l). If you care about getting the main loop split for every line, you can also code it but, that's just hacking down the hack. I wouldn't know how to programatically "really" split the main loop. Other than using other hacks like an invisible notebook and NotebookEvaluate, hummm $\endgroup$
    – Rojo
    Commented Jul 28, 2013 at 3:00
  • $\begingroup$ The main loop splitting seeeeems to me happens before the CellEvaluationFunction gets evaluated by the kernel, so I don't have high hopes for an unhacky clean solution. But who knows $\endgroup$
    – Rojo
    Commented Jul 28, 2013 at 3:06
2
$\begingroup$

I don't think you can modify the CellEvaluationFunction to achieve your goal. On the other hand, you can modify MakeExpression instead, as MakeExpression is called on each line of input. So:

MakeExpression[x_,form_] /; !TrueQ@flag && TrueQ@override := Block[{flag=True},
    List/@MakeExpression[x,form]
]

The above code will add a List wrapper to every evaluated expression, but only when the override variable is True:

override = True;
2+2
5+7

{4}

{12}

Setting override back to False will restore the normal behavior:

override = False;
2+2
5+7

{Null}

4

12

$\endgroup$
1
$\begingroup$

The front-end sends a EnterExpressionPacket to the kernel, which contains a expression like MakeExpression[]. As you had found, it has a different behavior to the real MakeExpression which exposed to users.

However, there is a kernel function for users which is able to handle multi-line input:

BoxForm`TopLevelMakeExpression

But it's still not exactly the real default one. For any CellEvaluationFunction except MakeExpression, the kernel

  • always single ReturnExpressionPacket except multiple packets
  • always use ReturnExpressionPacket instead of ReturnInputFormPacket etc.
  • never send OutputNamePacket["Out[1]= //MatrixForm"] etc. for $OutputForms

Seems that CellEvaluationFunction is not a interface good enough for user-customization.

$\endgroup$

Your Answer

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

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