كيفية عمل نظير لـ InString[]؟
-
15-11-2019 - |
سؤال
لقد اكتشفت ذلك InString[]
لا يعمل في MathLink
الوضع عند إرسال المدخلات مع EnterExpressionPacket
header.لذلك أحتاج إلى تحديد وظيفتي الخاصة التي تُرجع سطر الإدخال السابق.إحدى الطرق التي قمت بتطويرها here
لا يعمل في بعض الحالات:
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]
ولقد حصلت للتو على إجابة السؤال InString
في MathLink
الوضع من تود جايلي (أبحاث ولفرام):
يتم تعيين التعليمات فقط عند استخدام EnterTextPacket ، وليس enterexpressionpacket.لا يوجد شكل سلسلة من الإدخال عند إرسال 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:
في التعليقات على السؤال الرئيسي، اقترح ليونيد شيفرين حلاً أفضل بكثير:
getLastInput :=
Block[{RuleDelayed},SetAttributes[RuleDelayed,HoldAllComplete];
With[{line=$Line-1},HoldComplete[In[line]]/.DownValues[In]]]
انظر التعليقات للحصول على التفاصيل.
تحرير 3:يمكن تحسين الكود الأخير عن طريق الاستبدال HoldComplete
بواسطة مزدوجة HoldForm
:
getLastInput :=
Block[{RuleDelayed},SetAttributes[RuleDelayed,HoldAllComplete];
With[{line=$Line-1},HoldForm@HoldForm[In[line]]/.DownValues[In]]]
الفكرة مأخوذة من العرض الذي قدمه روبي فيليجاس من شركة Wolfram Research في مؤتمر المطورين عام 1999.راجع القسم الفرعي "الحجز الكامل:متغير غير قابل للطباعة من HoldComplete (تمامًا كما هو الحال مع HoldForm)" في "العمل مع التعبيرات غير المقيَّمة" تم نشر دفتر الملاحظات هنا.
نصائح أخرى
سأستخدم $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]]}]
لقد وجدت للتو طريقة أبسط ولكنها خطيرة:
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]]
هل يعرف أحد طريقة لجعلها آمنة؟