您当然可以这样做。这是一种方法:
exportCode[fname_String] :=
Function[code,
Export[fname, ToString@HoldForm@FullForm@code, "String"],
HoldAllComplete]
例如:
fn = exportCode["C:\\Temp\\mmacode.m"];
fn[
Clear[getWordsIndices];
getWordsIndices[sym_, words : {__String}] :=
Developer`ToPackedArray[words /. sym["Direct"]];
];
并将其作为字符串导入:
In[623]:= Import["C:\\Temp\\mmacode.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 中有许多技术可用于进行元编程和avoid 过早评估。我在this 回答中描述了我想到的一个,但还有很多其他的。由于您可以对已解析的代码进行操作并使用 Mathematica 中的模式匹配,您可以节省很多。您可以浏览 SO Mathematica 标签(过去的问题)并找到许多元编程和评估控制的示例。
编辑
使用自动评估符号来减轻您的痛苦(实际上只有少数,Infinity 就是其中之一)。如果您只需要获取给定符号的符号名称,那么此功能将有所帮助:
unevaluatedSymbolName = Function[sym, SymbolName@Unevaluated@sym, HoldAllComplete]
你把它当作
In[638]:= unevaluatedSymbolName[Infinity]//InputForm
Out[638]//InputForm="Infinity"
或者,您可以通过SetAttributes 简单地将HoldFirst 属性添加到SymbolName 函数。一种方法是在全球范围内这样做:
SetAttributes[SymbolName,HoldFirst];
SymbolName[Infinity]//输入形式
然而,全局修改内置函数是危险的,因为它可能对 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}]]
在这种情况下进行替换的一般方法是使用保留属性(请参阅this 答案)和保留表达式中的替换(请参阅this 问题)。对于手头的情况:
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"}]]
实际上,整个答案很好地展示了各种元编程技术。根据我自己的经验,我可以将您引导至 this、this、this、this 和 this 我的答案,其中元编程对于解决我正在解决的问题至关重要。您还可以通过 Mathematica 中所有函数都带有 Hold 属性的函数的比例来判断——如果记忆对我有用的话,这大约是 10-15%。所有这些函数实际上都是宏,对代码进行操作。对我来说,这是一个非常具有指示性的事实,它告诉我 Mathematica 非常依赖于它的元编程设施。