3

我发现在发送带有标题的输入时,InString[]它在模式下不起作用。所以我需要定义我自己的函数来返回前一个输入行。我开发的一种方法在某些情况下不起作用:MathLinkEnterExpressionPackethere

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]

但是修改内置函数通常不是一个好主意。有一个更好的方法吗?

4

3 回答 3

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)那里得到了关于InStringin mode 问题的答案:MathLink

InString 仅在使用 EnterTextPacket 时分配,而不是 EnterExpressionPacket。发送 EnterExpressionPacket 时没有字符串形式的输入(根据定义,其内容已经是一个表达式)。

编辑:

我刚刚发现我的代码不适用于带有 head 的输入表达式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:

在对主要问题的评论中,Leonid Shifrin 提出了更好的解决方案:

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

详情见评论。

编辑3: 最后一个代码可以通过替换为更好HoldComplete的 double HoldForm

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

这个想法来自 Wolfram Research 的 Robby Villegas 在 1999 年开发者大会上的演讲。请参阅此处发布的“使用未评估的表达式”笔记本中的“HoldCompleteForm:HoldComplete 的非打印变体(就像 HoldForm 一样)”小节。

于 2011-02-18T07:12:14.950 回答
1

我会使用$Preand$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]]}]
于 2011-02-18T14:36:00.560 回答
0

I just have found simpler but dangerous way:

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

Does anybody know a way to make it safe?

于 2011-02-18T11:15:50.557 回答