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(其内容
根据定义,它已经是一个
表达式)
编辑:
我刚刚发现我的代码不能与headEvaluate
的输入表达式一起使用。解决方案是将我的代码中的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
替换为doubleHoldForm
,可以使最后一个代码变得更好:
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]]}]