如何模拟 InString[]?

发布于 2024-10-18 03:18:15 字数 838 浏览 1 评论 0原文

我发现使用 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]

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

I have discovered that InString[] does not work in MathLink mode when sending input with EnterExpressionPacket header. So I need to define my own function that returns previous input line. One way I have developed here does not work in some cases:

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

This is because RuleDelayed has no HoldAllComplete attribute. Adding this attribute makes this OK:

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]

But modifying built-in functions generally is not a good idea. Is there a better way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

忘羡 2024-10-25 03:18:15

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

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) 那里得到了关于 MathLink 模式下 InString 问题的答案:

InString 仅在使用时才赋值
EnterTextPacket,不是
输入表达式包。没有
发送时输入的字符串形式
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:

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

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

有关详细信息,请参阅评论。

编辑3:
最后的代码可以通过用双 HoldForm 替换 HoldComplete 来做得更好:

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

这个想法取自 Wolfram Research 的 Robby Villegas 在 1999 年开发者大会上的演讲。请参阅 “使用未计算的表达式”笔记本发布于此处

It seems that I have solved the problem. Here is the function:

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]

And I just have got the answer to the question on InString in MathLink mode from Todd Gayley (Wolfram Research):

InString is only assigned when using
EnterTextPacket, not
EnterExpressionPacket. There is no
string form of the input when sending
EnterExpressionPacket (whose content
is, by definition, already an
expression).

EDIT:

I just have found that my code does not work with input expressions with head Evaluate. The solution is to replace HoldForm by HoldComplete in my code:

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

This works well. Another approach would be to unprotect HoldForm and set up attribute HoldAllComplete on it. I'm wondering why HoldForm does not have this attribute by default?

EDIT 2:

In the comments for the main question Leonid Shifrin suggested much better solution:

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

See comments for details.

EDIT 3:
The last code can be made even better for by replacing HoldComplete by double HoldForm:

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

The idea is taken from presentation by Robby Villegas of Wolfram Research at the 1999 Developer Conference. See subsection "HoldCompleteForm: a non-printing variant of HoldComplete (just as HoldForm is to Hold)" in "Working With Unevaluated Expressions" notebook posted here.

少女情怀诗 2024-10-25 03:18:15

我会使用 $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]]}]

I would use $Pre and $Line for this; unlike $PreRead, it's applied to input expressions, not input strings or box forms. All you need is to assign it a function that has the HoldAllComplete attribute, like this one which I've adapted from the example in the documentation:

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

I tested this with MathLink, and the behavior seems to be what you desired (I've elided some of the transcript to highlight the key point):

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]]}]
提赋 2024-10-25 03:18:15

我只是找到了更简单但危险的方法:

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

有人知道如何保证安全吗?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文