Wolfram mathematica 如何模拟InString[]?

Wolfram mathematica 如何模拟InString[]?,wolfram-mathematica,mathlink,Wolfram Mathematica,Mathlink,我发现当使用EnterExpressionPacket头发送输入时,InString[]在MathLink模式下不起作用。所以我需要定义我自己的函数来返回前面的输入行。我开发的一种方法在某些情况下不起作用: In[1]:= Unevaluated[2 + 2] With[{line = $Line - 1}, HoldForm[In[line]]] /. (DownValues[In]) Out[1]= Unevaluated[2 + 2] Out[2]= 2 + 2 这是因为RuleDela

我发现当使用
EnterExpressionPacket
头发送输入时,
InString[]
MathLink
模式下不起作用。所以我需要定义我自己的函数来返回前面的输入行。我开发的一种方法在某些情况下不起作用:

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]

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

看来我已经解决了这个问题。以下是函数:

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 输入文本包,而不是 输入expressionpacket。没有 发送时输入的字符串形式 EnterExpressionPackage(其内容 根据定义,它已经是一个 表达式)

编辑:

我刚刚发现我的代码不能与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一样)”小节。

我刚刚发现了更简单但危险的方法:

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]]
有人知道安全的方法吗?

我会使用和
$Line
;与
$PreRead
不同,它应用于输入表达式,而不是输入字符串或框形式。您只需为其分配一个具有
HoldAllComplete
属性的函数,就像我根据文档中的示例改编的函数:

SetAttributes[saveinputs, HoldAllComplete];
saveinputs[new_] :=
 With[{line = $Line},
  inputs[line] = HoldComplete[new]; new]
$Pre = saveinputs;
我用MathLink对此进行了测试,其行为似乎符合您的要求(为了突出重点,我省略了一些文字记录):


如果您仅在[$Line-1]中使用,结果将不进行评估[2+2],这是应该的。:)(当然,在这种情况下)@belisarius我知道,但我正在寻找通用的解决方案。@Alexey这里有一个更优雅的解决方案,最能说明我关于
HoldComplete
RuleDelayed
的观点:
getLastInput:=With[{line=$line-1},HoldForm[in[line]]/.Block[{RuleDelayed},SetAttributes[RuleDelayed,HoldAll];Map[HoldForm,DownValues[In],{2}]]
@Alexey但显然,还有更有趣的事情发生。也就是说,我们不能完全阻止
RuleDelayed
,因为它仍然会进行替换(也许不是关于
RuleDelayed
,而是关于替换运算符)。无论如何,我们可以利用这一点来产生更优雅的解决方案:
getLastInput:=Block[{RuleDelayed},SetAttributes[RuleDelayed,HoldAll];使用[{line=$line-1},HoldForm[In[line]]/.DownValues[In]]
。此处的相同注释-将
HoldForm
替换为
HoldComplete
,将
HoldAll
替换为
HoldAllComplete
,以处理
评估
@Alexey至少还有一种情况需要
HoldComplete
才能正确处理。下面是一个示例(使用基于
HoldForm
getLastInput
进行尝试):
Clear[a];a/:f_u[l,a]:=f[l,1];getLastInput
(同样,所有语句都在单独的行上。在本例中应该有4行,
a
占用单独的行)这可能不安全,因为
Trace
将重新评估输入。因此,如果输入评估的任何阶段包含副作用,您将以一种通常不可逆的方式改变全局状态-并且您没有简单的方法来确定副作用的存在或不存在。结果,在以下情况中,例如,
i=0;i++Trace[In[$Line-1]///Last
,(假设
i=0
i++
占用单独的行,注释格式不允许我这样做),
i
在调用
Trace
后变为2,而在此之前变为1。有趣的是[]上的
是如何工作的:它不会重新评估任何东西!但在某些情况下,[]
上的
很容易被破坏。例如在[General::newsym]上尝试
;完成[a];名称[“``*]”
。它不会生成创建符号
a
的消息!另一方面,
HoldComplete
似乎不应该创建新符号!您可能正在使用版本7,其中与创建新符号的事件处理相关的内容被破坏。它似乎已经在第8节中被修正了。关于新符号创建的一般机制,这发生在解析时,而不是求值时,因此
HoldComplete
是不相关的。如果要将符号的创建延迟到运行时,请使用
symbol[“symbol name”]
。我在这里举了一个使用它的例子:好主意!但是更正确的代码应该写成
SetAttributes[saveinputs,HoldAllComplete];saveinputs[new_]:=(输入[$Line]=HoldComplete[new];未赋值[new])$Pre=保存输入
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]]}]