3

ヘッダー付きの入力を送信するときに、モードInString[]で機能しないことを発見しました。したがって、前の入力行を返す独自の関数を定義する必要があります。私が開発した1つの方法は、場合によっては機能しません。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)からモードInStringでの質問に対する答えを得ました:MathLink

InStringは、EnterExpressionPacketではなく、EnterTextPacketを使用する場合にのみ割り当てられます。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]]

これはうまく機能します。もう1つのアプローチは、保護を解除HoldFormして属性を設定するHoldAllCompleteことです。なぜHoldFormデフォルトでこの属性がないのか疑問に思いますか?

編集2:

主な質問に対するコメントで、LeonidShifrinははるかに優れた解決策を提案しました。

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

このアイデアは、1999年の開発者会議でのWolframResearchのRobbyVillegasによるプレゼンテーションから取られています。ここに掲載されている「未評価の式の操作ノートブックのサブセクション「HoldCompleteForm:HoldCompleteの非印刷バリアント(HoldFormが保持するのと同じように)」を参照してください。

于 2011-02-18T07:12:14.950 に答える
1

私はこれに使用$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]]}]
于 2011-02-18T14:36:00.560 に答える
0

私はもっ​​と簡単だが危険な方法を見つけました:

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

誰かがそれを安全にする方法を知っていますか?

于 2011-02-18T11:15:50.557 に答える