(MathLink) Правильная обработка сообщений, генерируемых ведомым ядром

При работе с MathLink с ведомым ядром у меня проблема с правильным анализом TextPacket s. В частности, когда такой пакет соответствует Message, сгенерированному подчиненным ядром, я не понимаю, как правильно его обрабатывать. Мне нужен такой Messages для печати в оценочном ноутбуке, как если бы они были сгенерированы основным ядром (но с некоторой меткой, чтобы четко указать, что это происходит от подчиненного устройства). И мне нужно отделить TextPacket от Message от команды Print[]. Последнее мне нужно также правильно разобрать, напечатав их в оценочной записной книжке с небольшой отметкой, что она находится от подчиненного ядра.

Вот пример того, что происходит:

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

Message по умолчанию проходит через MathLink в форме:

TextPacket[                                 1
Power::infy: Infinite expression - encountered.
                                 0]

Это выглядит уродливо. Единственный способ сделать это лучше, чем я нашел, - это оценить в подчиненном ядре

$MessagePrePrint = InputForm;

Но я думаю, что должно быть более простое решение. В частности, при этом я получаю TextPacket с HoldForm внутри:

TextPacket[Power::infy: Infinite expression HoldForm[0^(-1)] encountered.]

Я не знаю, как преобразовать такую ​​строку в форму, подходящую для печати как Message.

P.S. Этот вопрос исходит из вопроса.

Ответ 1

Я хотел бы поделиться приятным взломом, предложенным Тоддом Гейли (Wolfram Research) в связи с данным вопросом. Возможно, для кого-то это будет полезно, как и для меня. Этот хак решает эту проблему довольно элегантным способом.

Один из способов - оставить FormatType в OutputForm для вычислений, но переопределить обработка сообщения временно переключитесь на StandardForm, так что только Выход сообщения возвращается 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]
           ]
        ]]

Вы получите экземпляр ExpressionPacket для содержимого сообщение. Чтобы напечатать это как ячейку Message в ноутбук:

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"]
[email protected][link]
LinkWrite[link, 
 Unevaluated[
  EnterExpressionPacket[$MessagePrePrint = ToBoxes[{##}] &; Print[a]; 
   1/0; Print[b]]]]
While[[email protected][packet = LinkRead[link], InputNamePacket[_]], 
 Print[packet]]