(MathLink) Корректная обработка сообщений, генерируемых ведомым ядром - PullRequest
3 голосов
/ 15 февраля 2011

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

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

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;

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

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

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

PS Этот вопрос возник из этого вопроса.

Ответы [ 2 ]

4 голосов
/ 01 марта 2011

Я хотел бы поделиться хорошим взломом, предложенным Тоддом Гейли (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 для содержимого сообщение. Чтобы напечатать это как ячейку сообщения в ноутбук:

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 голосов
/ 19 февраля 2011

Выражение всегда присутствует в 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]]
...