Changing behavior of General::stop and the main loop
On the Documentation page
for General::stop
we read:
This message is generated after the indicated message has been generated for the third time in a single evaluation.
Messages are suppressed to prevent redundant or repetitive messages in long calculations.
My problem is that when working through MathLink
I pass every point as a single evaluation and so General::stop
never appears.
For example, if I define:
link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
f[z_?NumericQ] := (Print@LinkRead[link];
LinkWrite[link,
Unevaluated[
EnterExpressionPacket[NIntegrate[Sin[1/x], {x, .001, z}]]]];
While[Head[packet = LinkRead[link]] =!= OutputNamePacket,
Print[packet]]; First@LinkRead[link]);
Plot[f[z], {z, 1, 10}, PlotPoints -> 6, MaxRecursion -> 0]
I get as many Message
packets as many evaluations of f[z]
. Of course I would like message generarion to be stopped in the slave kernel by General::stop
after generating the same message 3 times. Is there a way to achieve this?
On the documentation page fo开发者_开发技巧r $MessageList
we read that
With the standard Mathematica main loop, $MessageList is reset to {} when the processing of a particular input line is complete.
And on the page tutorial/Messages
we read:
In every computation you do, Mathematica maintains a list $MessageList of all the messages that are produced. In a standard Mathematica session, this list is cleared after each line of output is generated.
May be this is a reason why General::stop
does not appear? If it is true is there a way to control this aspect of the Main Loop? Is there a way to create such a non-standard Mathematica session?
EDIT:
It seems that my supposition was right. If we will clear $MessageList
after every Message, then General::stop
never appears:
Unprotect[$MessageList]
Do[$MessageList = {}; 1/0, {10}]
So the question remains: how to disable automatic clearing $MessageList
after generating output?
There are probably better solutions, but here is one that seems to work. As far as I understand, all that matters is that you have some persistent variable in the slave kernel that accumulates messages.
link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
f[z_?NumericQ] :=
(Print@LinkRead[link];
LinkWrite[link, Unevaluated[EnterExpressionPacket[
If[! ValueQ[oldMessageList], oldMessageList = {}];
Block[{$MessageList = oldMessageList},
Module[{result},
oldMessageList =
Join[oldMessageList, (result =
NIntegrate[Sin[1/x], {x, .001, z}]; $MessageList)];
result
]]]]];
While[Head[packet = LinkRead[link]] =!= OutputNamePacket,
Print[packet]]; First@LinkRead[link]);
Plot[f[z], {z, 1, 10}, PlotPoints -> 6, MaxRecursion -> 0]
HTH
I have found the solution. It exploites again elegant hack by Todd Gayley
. Here it is (of course, it must be evaluated in the slave kernel):
$globalMessageList = {};
Unprotect[Message];
Message[args___] :=
Block[{$inMsg = True, $MessageList = $globalMessageList},
Message[args];
$globalMessageList = $MessageList;
] /; ! TrueQ[$inMsg];
Protect[Message];
One can fully emulate standard behavior of Messages in the slave kernel by checking the current value of $Line
and comparing it with previous value:
If[TrueQ[$Line > lastLine],
LinkWrite[$kern,
Unevaluated[ExpressionPacket[$globalMessageList = {};]]];
LinkRead[$kern]]; lastLine = $Line;
:)
精彩评论