我发现使用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]
但是修改内置函数通常不是一个好主意。有更好的方法吗?
答案 0 :(得分:2)
似乎我已经解决了这个问题。这是功能:
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]
我刚从Todd Gayley(Wolfram Research)获得InString
MathLink
模式问题的答案:
仅在使用时分配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]]]
这个想法来自1999年开发者大会上Wolfram Research的Robby Villegas的演讲。请参阅"Working With Unevaluated Expressions"发布的here笔记本中的“HoldCompleteForm:HoldComplete的非打印变体(就像HoldForm要保留)”小节。
答案 1 :(得分:1)
我会使用$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]]}]
答案 2 :(得分:0)
我刚刚找到了更简单但危险的方式:
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]]
有人知道如何安全吗?