(MathLink)正确处理由从属内核生成的消息

3
当使用从属内核的MathLink进行工作时,我在正确解析TextPacket时遇到了问题。特别是当这样的数据包对应于从属内核生成的Message时,我完全不知道如何正确处理它。我需要将这样的Message打印在评估笔记本中,就像它们是由主内核生成的(但带有一些标记,以明确它来自从属内核)。我需要将对应于MessageTextPacket与仅用于Print[]命令的TextPacket分开。后者我也需要正确解析,并在评估笔记本中打印它们,附上一个小标记表示它来自从属内核。

以下是发生的情况示例:

link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
Print@LinkRead[link]
LinkWrite[link, 
 Unevaluated[EnterExpressionPacket[Print[a]; 1/0; Print[b]]]]
While[Not@MatchQ[packet = LinkRead[link], InputNamePacket[_]], 
 Print[packet]]

默认情况下,Message以以下形式通过MathLink传递:
TextPacket[                                 1
Power::infy: Infinite expression - encountered.
                                 0]

看起来很丑。我发现唯一让它变得更好的方法是在从属内核中进行评估。

$MessagePrePrint = InputForm;

但我认为应该有更直接的解决方案。特别是当处理这种方式时,我会得到内部带有HoldFormTextPacket
TextPacket[Power::infy: Infinite expression HoldForm[0^(-1)] encountered.]

我不知道如何将这样的字符串转换为适合打印为 Message 的形式。
附注:这个问题来自于那个问题。
2个回答

4

我想分享一种由Wolfram Research的Todd Gayley提出的不错技巧,与给定问题有关。对于某些人来说,这个技巧可能会像对我一样有用。这个技巧以相当优雅的方式解决了问题。

一种技术是在计算时保留FormatType为OutputForm,但覆盖Message的处理方法以临时切换到StandardForm,这样只有Message输出会以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]

高级方法:所有内容都以StandardForm形式打印

为了使除输出之外的所有内容都以StandardForm形式返回,我们可以在从属内核中以特殊方式重新定义变量$Pre$Post(以下代码应该在从属内核中评估):

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];

2
表达式始终以HoldForm形式存在,但默认的$MessagePrePrint不渲染它。尝试评估。
HoldForm[1/0]

InputForm[%]

实现你想要的行为的一种方法是实现自己的盒子渲染器。要查看渲染器需要处理的内容,请设置

$MessagePrePrint = ToBoxes[{##}] &

在从属中。就像这样:
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]]

除了实现附加的框渲染器外,还有更好的方法吗? - Alexey Popkov
1
ن½؟用ToStringه¹¶ه¤„çگ†ç»“و‍œه¦‚ن¸‹$MessagePrePrint = StringReplace[ToString[InputForm[#]], "HoldForm[" ~~ Shortest[x___] ~~ "]" :> x] & - Sasha
它更简单,但下标、上标和命名字符在 InputForm 中看起来很丑。我希望有一些“神奇”的函数可以强制从属核以便利的形式发送消息(例如作为整个 Cell 内容,无需进一步呈现)。如果创建框渲染器的想法没有替代方案,我需要一些帮助。例如,我不明白为什么这会生成错误:ToExpression[ToString[ToBoxes[HoldForm[Infinity - Infinity]]]](它来自于输入 Infinity - Infinity 生成的消息)。 - Alexey Popkov
1
@AlexeyPopkov 问题在于ToString默认使用OutputForm,这保证了与ToExpression的兼容性,你需要使用StandardForm或InputForm。例如ToExpression[ ToString[ToBoxes[HoldForm[Infinity - Infinity]], InputForm]] - Sasha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接