Как сделать аналог InString []? - PullRequest
3 голосов
/ 18 февраля 2011

Я обнаружил, что InString[] не работает в режиме MathLink при отправке ввода с заголовком EnterExpressionPacket.Поэтому мне нужно определить свою собственную функцию, которая возвращает предыдущую строку ввода.Один из разработанных мной способов here не работает в некоторых случаях:

In[1]:= Unevaluated[2 + 2]
With[{line = $Line - 1}, HoldForm[In[line]]] /. (DownValues[In])
Out[1]= Unevaluated[2 + 2]
Out[2]= 2 + 2

Это потому, что RuleDelayed не имеет атрибута HoldAllComplete.Добавление этого атрибута делает это нормально:

In[1]:= Unprotect[RuleDelayed];
SetAttributes[RuleDelayed, HoldAllComplete];
Protect[RuleDelayed];
Unevaluated[2 + 2]
With[{line = $Line - 1}, HoldForm[In[line]]] /. DownValues[In]

Out[4]= Unevaluated[2 + 2]

Out[5]= Unevaluated[2 + 2]

Но изменение встроенных функций обычно не является хорошей идеей.Есть ли лучший способ сделать это?

Ответы [ 3 ]

2 голосов
/ 18 февраля 2011

Кажется, я решил проблему.Вот функция:

In[1]:=
getLastInput := Module[{num, f},
    f = Function[{u, v},
        {u /. {In -> num, HoldPattern -> First}, HoldForm[v]}, HoldAllComplete];
    First@Cases[
        Block[{RuleDelayed = f}, DownValues[In]],
        {$Line - 1, x_} -> x, {1}, 1]]

In[2]:=
Unevaluated[2+2]
getLastInput

Out[2]=
Unevaluated[2+2]

Out[3]=
Unevaluated[2+2]

И я только что получил ответ на вопрос о InString в режиме MathLink от Тодда Гейли (Wolfram Research):

InString назначается только при использовании EnterTextPacket, а не EnterExpressionPacket.При отправке EnterExpressionPacket отсутствует строковая форма ввода (содержимое которого по определению уже является выражением).

РЕДАКТИРОВАТЬ:

У меня просто естьобнаружил, что мой код не работает с входными выражениями с головой Evaluate.Решение состоит в том, чтобы заменить HoldForm на HoldComplete в моем коде:

getLastInput := Module[{num, f},
    f = Function[{u, v},
        {u /. {In -> num, HoldPattern -> First}, HoldComplete[v]}, HoldAllComplete];
    First@Cases[
        Block[{RuleDelayed = f}, DownValues[In]],
        {$Line - 1, x_} -> x, {1}, 1]]

Это хорошо работает.Другой подход - снять защиту HoldForm и установить для нее атрибут HoldAllComplete.Мне интересно, почему HoldForm не имеет этого атрибута по умолчанию?

РЕДАКТИРОВАТЬ 2:

В комментариях к основному вопросу Леонид Шифрин предложил гораздо лучшее решение:

getLastInput := 
 Block[{RuleDelayed},SetAttributes[RuleDelayed,HoldAllComplete];
  With[{line=$Line-1},HoldComplete[In[line]]/.DownValues[In]]]

Подробнее см. В комментариях.

РЕДАКТИРОВАТЬ 3: Последний код можно сделать еще лучше, заменив HoldComplete на двойной HoldForm:

getLastInput := 
 Block[{RuleDelayed},SetAttributes[RuleDelayed,HoldAllComplete];
  With[{line=$Line-1},HoldForm@HoldForm[In[line]]/.DownValues[In]]]

Идея взята из презентации Робби Виллегаса из Wolfram Research на конференции разработчиков 1999 года.См. Подраздел «HoldCompleteForm: вариант« HoldComplete »без печати»

1 голос
/ 18 февраля 2011

Я бы использовал $Pre и $Line для этого;в отличие от $PreRead, он применяется к выражениям ввода , а не к строкам ввода или блочным формам.Все, что вам нужно, - это назначить ей функцию с атрибутом HoldAllComplete, как этот, который я адаптировал из примера в документации:

SetAttributes[saveinputs, HoldAllComplete];
saveinputs[new_] :=
 With[{line = $Line},
  inputs[line] = HoldComplete[new]; new]
$Pre = saveinputs;

Я проверил это с помощью MathLink и поведениякажется, что вы хотели (я исключил некоторые из стенограммы, чтобы выделить ключевой момент):

In[14]:= LinkWrite[link,
 Unevaluated[
  EnterExpressionPacket[
   SetAttributes[saveinputs, HoldAllComplete];
   saveinputs[new_] :=
    With[{line = $Line},
     inputs[line] = HoldComplete[new]; new];
   $Pre = saveinputs;]]]

In[15]:= LinkRead[link]
Out[15]= InputNamePacket["In[2]:= "]

In[20]:= LinkWrite[link,
 Unevaluated[EnterExpressionPacket[Evaluate[1 + 1]]]]

In[21]:= LinkRead[link]
Out[21]= OutputNamePacket["Out[2]= "]

In[21]:= LinkRead[link]
Out[21]= ReturnExpressionPacket[2]

In[24]:= LinkWrite[link, Unevaluated[EnterExpressionPacket[DownValues[inputs]]]]

In[26]:= LinkRead[link]
Out[26]= ReturnExpressionPacket[
  {HoldPattern[inputs[2]] :> HoldComplete[Evaluate[1 + 1]], 
   HoldPattern[inputs[3]] :> HoldComplete[DownValues[inputs]]}]
0 голосов
/ 18 февраля 2011

Я только что нашел более простой, но опасный способ:

In[3]:= Unevaluated[2 + 2]
Trace[In[$Line - 1]] // Last
Trace[In[$Line - 1]] // Last

Out[3]= Unevaluated[2 + 2]

Out[4]= Unevaluated[2 + 2]

During evaluation of In[3]:= $RecursionLimit::reclim: Recursion depth of 256 exceeded. >>

During evaluation of In[3]:= $RecursionLimit::reclim: Recursion depth of 256 exceeded. >>

During evaluation of In[3]:= $IterationLimit::itlim: Iteration limit of 4096 exceeded. >>

Out[5]= Hold[In[$Line-1]]

Кто-нибудь знает способ сделать его безопасным?

...