以`FullForm`语法保存Mathematica代码

我需要在一个大型的Mathematica代码库(数十万行代码)上进行元编程,并且不想编写完整的解析器,所以我想知道如何最好地从Mathematica笔记本中获取代码以易于解析的语法。

是否可以使用FullForm语法导出Mathematica笔记本,或者是否将所有定义保存在FullForm语法中?

Save的文档说它只能以InputForm语法输出,这对解析来说是不平凡的。

到目前为止,我最好的解决方案是评估笔记本,然后使用DownValues来提取带有参数的重写规则(但这会忽略符号定义),如下所示:

DVs[_] := {}
DVs[s_Symbol] := DownValues[s]
stream = OpenWrite["FullForm.m"];
WriteString[stream, 
  DVs[Symbol[#]] & /@ Names["Global`*"] // Flatten // FullForm];
Close[stream];

到目前为止,我已经尝试了各种方法,但都没有效果。 Mathematica中的元编程似乎非常困难,因为它不断评估我想保持未评估的东西。 例如,我想使用SymbolName[Infinity]来获取无穷大符号的字符串名称,但Infinity会被计算为非符号,并且对SymbolName的调用会因错误而死亡。 因此,我希望以更合适的语言进行元编程。

编辑

最好的解决方案似乎是手动将笔记本保存为包(.m)文件,然后使用以下代码翻译它们:

stream = OpenWrite["EverythingFullForm.m"];
WriteString[stream, Import["Everything.m", "HeldExpressions"] // FullForm];
Close[stream];

可以从笔记本的CodeInput单元格中提取完整形式的表达式,如下所示:

$exprs =    
  Cases[
    Import["mynotebook.nb", "Notebook"]
  , Cell[content_, "Code"|"Input", ___] :>
      ToExpression[content, StandardForm, HoldComplete]
  , Infinity
  ] //
  Flatten[HoldComplete @@ #, 1, HoldComplete] & //
  FullForm

$exprs被分配了表达式read,包装在Hold以防止评估。 $exprs然后可以被保存到一个文本文件中:

Export["myfile.txt", ToString[$exprs]]

包文件(.m)通过这种方式稍微容易阅读:

Import["mypackage.m", "HeldExpressions"] //
Flatten[HoldComplete @@ #, 1, HoldComplete] &

你当然可以做到这一点。 这是一种方法:

exportCode[fname_String] := 
 Function[code, 
    Export[fname, ToString@HoldForm@FullForm@code, "String"], 
    HoldAllComplete]

例如:

fn = exportCode["C:Tempmmacode.m"];
fn[
  Clear[getWordsIndices];
  getWordsIndices[sym_, words : {__String}] := 
      Developer`ToPackedArray[words /. sym["Direct"]];
];

并将其作为字符串导入:

In[623]:= Import["C:Tempmmacode.m","String"]//InputForm
Out[623]//InputForm=
"CompoundExpression[Clear[getWordsIndices], SetDelayed[getWordsIndices[Pattern[sym, Blank[]], 
Pattern[words, List[BlankSequence[String]]]], Developer`ToPackedArray[ReplaceAll[words, 
sym["Direct"]]]], Null]"

然而,考虑到Mathematica非常适合这种情况,使用其他语言为Mathematica进行元编程听起来很可笑。 Mathematica中有许多技术可用于元编程并避免过早评估。 在我的脑海里,我想到了一个这样的答案,但还有很多其他的东西。 由于您可以对分析的代码进行操作并在Mathematica中使用模式匹配,因此可以节省很多。 您可以浏览SO Mathematica标签(过去的问题),并找到很多元编程和评估控制的例子。

编辑

使用自动评估符号来减轻您的痛苦(实际上只有少数符号, Infinity就是其中之一)。如果您只需要为给定符号获取符号名称,则此函数将有助于:

unevaluatedSymbolName =  Function[sym, SymbolName@Unevaluated@sym, HoldAllComplete]

你使用它

In[638]:= unevaluatedSymbolName[Infinity]//InputForm
Out[638]//InputForm="Infinity"

或者,您可以通过SetAttributes简单地将HoldFirst属性添加到SymbolName函数。 一种方法是在全球范围内进行:

SetAttributes [符号名称,HoldFirst]; 符号名称[无限远] // InputForm

然而,在全球范围内修改内置函数是很危险的,因为它可能对像Mathematica这样的大系统产生不可预测的影响:

ClearAttributes[SymbolName, HoldFirst];

这是一个在本地使用的宏:

ClearAll[withUnevaluatedSymbolName];
SetAttributes[withUnevaluatedSymbolName, HoldFirst];
withUnevaluatedSymbolName[code_] :=
  Internal`InheritedBlock[{SymbolName},
     SetAttributes[SymbolName, HoldFirst];
     code]

现在,

In[649]:= 
withUnevaluatedSymbolName[
   {#,StringLength[#]}&[SymbolName[Infinity]]]//InputForm

Out[649]//InputForm=  {"Infinity", 8}

你也可能希望在一段代码中进行一些替换,比如用名字替换给定的符号。 下面是一个示例代码(我将其包装在Hold以阻止其评估):

c = Hold[Integrate[Exp[-x^2], {x, -Infinity, Infinity}]]

在这种情况下进行替换的一般方法是使用保留属性(请参阅此答案)和替换内部保留的表达式(请参阅此问题)。 对于手头的情况:

In[652]:= 
withUnevaluatedSymbolName[
       c/.HoldPattern[Infinity]:>RuleCondition[SymbolName[Infinity],True]
]//InputForm

Out[652]//InputForm=
Hold[Integrate[Exp[-x^2], {x, -"Infinity", "Infinity"}]]

尽管这不是唯一的方法。 除了使用上面的宏,我们还可以将对SymbolName的修改编码到规则本身中(这里我使用的是更为罗嗦的形式(Trott - Strzebonski技巧)就地评估,但您也可以使用RuleCondition

ClearAll[replaceSymbolUnevaluatedRule];
SetAttributes[replaceSymbolUnevaluatedRule, HoldFirst];
replaceSymbolUnevaluatedRule[sym_Symbol] :=
  HoldPattern[sym] :> With[{eval = SymbolName@Unevaluated@sym}, eval /; True];

现在,例如:

In[629]:= 
Hold[Integrate[Exp[-x^2],{x,-Infinity,Infinity}]]/.
      replaceSymbolUnevaluatedRule[Infinity]//InputForm
Out[629]//InputForm=
    Hold[Integrate[Exp[-x^2], {x, -"Infinity", "Infinity"}]]

实际上,这整个答案是各种元编程技术的很好的例子。 根据我自己的经验,我可以将您引导到这个,这个,这个,这个和我的答案,元编程对解决我正在解决的问题至关重要。 您还可以通过Mathematica中的功能分数来判断所有功能的保留属性 - 如果记忆功能良好,大约10-15%。 所有这些函数都是有效的宏,在代码上运行。 对我来说,这是一个非常指示性的事实,告诉我Mathematica以其元编程设施为基础。

链接地址: http://www.djcxy.com/p/35603.html

上一篇: Save Mathematica code in `FullForm` syntax

下一篇: Could the notebook StyleSheet change the code behaviour?