如何模拟InString []? [英] How to make an analog of InString[]?
问题描述
我发现发送带有EnterExpressionPacket
标头的输入时InString[]
在MathLink
模式下不起作用.因此,我需要定义自己的函数以返回上一个输入行.我开发 here
的一种方法在某些情况下不起作用:
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
这是因为RuleDelayed
没有HoldAllComplete
属性.添加此属性可以使此操作正常:
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?
推荐答案
看来我已经解决了问题.功能如下:
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]
Todd Gayley(Wolfram Research)以MathLink
模式在MathLink
模式下得到了关于InString
问题的答案:
And I just have got the answer to the question on InString
in MathLink
mode from Todd Gayley (Wolfram Research):
仅在使用时分配InString EnterTextPacket,不是 EnterExpressionPacket.没有 发送时输入的字符串形式 EnterExpressionPacket(其内容 根据定义,已经是 表达式).
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).
我刚刚发现我的代码不适用于头部为Evaluate
的输入表达式.解决方案是在我的代码中将HoldForm
替换为HoldComplete
:
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]]
这很好.另一种方法是取消保护HoldForm
并在其上设置属性HoldAllComplete
.我想知道为什么HoldForm
默认不具有此属性?
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?
在对主要问题的评论中,列昂尼德·希弗林(Leonid Shifrin)提出了更好的解决方案:
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.
通过将HoldComplete
替换为双HoldForm
,可以使最后的代码更好:
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]]]
这个想法来自Wolfram Research的Robby Villegas在1999年开发者大会上的演讲.请参阅笔记本此处.
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.
这篇关于如何模拟InString []?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!