(MathLink) Correct handling of Messages generated by slave kernel

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-01 00:03:29

I would like to share a nice hack proposed by Todd Gayley (Wolfram Research) in connection with the given question. Perhaps for somebody it will be useful as also for me. This hack solves the problem in question in rather elegant way.

One technique is to leave the FormatType at OutputForm for computations, but override the handling of Message to temporarily switch to StandardForm, so that only Message output comes back in StandardForm:

LinkWrite[link,
        Unevaluated[EnterExpressionPacket[
            Unprotect[Message];
            Message[args___]:=
               Block[{$inMsg = True, result},
                  SetOptions[$Output, FormatType->StandardForm];
                  result = Message[args];
                  SetOptions[$Output, FormatType->OutputForm];
                  result
               ] /; !TrueQ[$inMsg]
           ]
        ]]

You will get back an ExpressionPacket for the content of a message. To print that as a Message cell in the notebook:

cell = Cell[<the ExpressionPacket>, "Message", "MSG"]
CellPrint[cell]

Advanced approach: everything is printed in the StandardForm

For having everything except output returned in StandardForm we could redefine variables $Pre and $Post in the slave kernel in a special way (the following code should be evaluated in the slave kernel):

SetOptions[$Output, {PageWidth -> 72, FormatType -> StandardForm}];
(*$inPost is needed for tracing mode compatibility 
(could be switched on by evaluating On[] in the slave kernel) 
in which Messages are printed during evaluation of $Post.*)
$inPost = False; Protect[$inPost];
$Pre := Function[inputexpr, 
  SetOptions[$Output, FormatType -> StandardForm]; 
  Unevaluated[inputexpr], HoldAllComplete];
$Post := Function[outputexpr, 
  Block[{$inPost = True}, 
   SetOptions[$Output, FormatType -> OutputForm]; 
   Unevaluated[outputexpr]], HoldAllComplete];
Protect[$Pre]; Protect[$Post];
$inMsg = False; Protect[$inMsg];
Unprotect[Message];
Message[args___] /; $inPost := Block[{$inMsg = True},
    SetOptions[$Output, FormatType -> StandardForm];
    Message[args];
    SetOptions[$Output, FormatType -> OutputForm]] /; ! $inMsg;
Protect[Message];

The expression comes in HoldForm always, but with the default $MessagePrePrint it is not rendered. Try evaluating

HoldForm[1/0]

InputForm[%]

One way to achieve your desired behavior would be to implement your own box renderer. To see that the renderer has to process, set

$MessagePrePrint = ToBoxes[{##}] &

in the slave. Like so:

link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
Print@LinkRead[link]
LinkWrite[link, 
 Unevaluated[
  EnterExpressionPacket[$MessagePrePrint = ToBoxes[{##}] &; Print[a]; 
   1/0; Print[b]]]]
While[Not@MatchQ[packet = LinkRead[link], InputNamePacket[_]], 
 Print[packet]]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!