Wolfram mathematica Mathematica什么时候创建新符号?

Wolfram mathematica Mathematica什么时候创建新符号?,wolfram-mathematica,Wolfram Mathematica,你好 我之前认为Mathematica在将输入字符串(分配给InString)转换为输入表达式(分配给中的)的阶段,在当前$Context中创建了新符号。但一个简单的例子打破了这一解释: In[1]:= ?f During evaluation of In[1]:= Information::notfound: Symbol f not found. >> In[2]:= Names["`*"] Out[2]= {} In[3]:= DownValues[In]//First InS

你好

我之前认为Mathematica在将输入字符串(分配给
InString
)转换为输入表达式(分配给
中的
)的阶段,在当前
$Context
中创建了新符号。但一个简单的例子打破了这一解释:

In[1]:= ?f
During evaluation of In[1]:= Information::notfound: Symbol f not found. >>
In[2]:= Names["`*"]
Out[2]= {}
In[3]:= DownValues[In]//First
InString[1]
Names["`*"]
Out[3]= HoldPattern[In[1]]:>Information[f,LongForm->False]
Out[4]= \(? f\)
Out[5]= {}
您可以看到,
$ContextPath
中没有符号
f
,尽管它已在[1]
中的
定义中使用

此示例表明,在Mathematica中,原则上可以使用
$ContextPath
中不存在的符号进行定义,而不创建它们。这可能是避免使用
symbol
创建符号的有趣替代方法:

In[9]:= ff := Symbol["f"]
Names["`*"]
Out[10]= {"ff"}
有人能解释一下Mathematica在评估过程中的哪些条件和阶段创造了新的符号吗

编辑 正如Sasha在对这个问题的评论中所注意到的,实际上,默认样式表Core.nb中的输出单元格的默认设置
ShowStringCharacters->False
欺骗了我,并且错过了
FullForm
输出的
DownValues[in]//First
。实际上,符号
f
未用于[1]
的定义中,我们也可以通过使用
InputForm
看到:

In[1]:= ?f
DownValues[In]//First//InputForm
During evaluation of In[1]:= Information::notfound: Symbol f not found. >>
Out[2]//InputForm=
HoldPattern[In[1]] :> Information["f", LongForm -> False]
对不起,我的声明太仓促了

所以现在的问题是Mathematica决定在哪个阶段创建新的
符号
,以及我们如何防止它? 例如,在上面的示例中,我们输入
f
作为
Symbol
,但Mathematica将其转换为
String
,而不创建新符号。这是
MakeExpression
的内置行为:

In[1]:= ?f
InputForm[MakeExpression[ToExpression@InString[1], StandardForm]]

During evaluation of In[1]:= Information::notfound: Symbol f not found. >>

Out[2]//InputForm=
HoldComplete[Information["f", LongForm -> False]]
In[1]:= MakeExpression[My`boxes_,My`f_]/;!TrueQ[My`$InsideMakeExpression]:=Block[{My`$InsideMakeExpression=True},Print[$Line];Print[DownValues[InString][[All,1]]];Print[DownValues[In][[All,1]]];Print[Names["`*"]];MakeExpression[My`boxes,My`f]];
In[2]:= a
During evaluation of In[2]:= 2
During evaluation of In[2]:= {HoldPattern[InString[1]]}
During evaluation of In[2]:= {HoldPattern[In[1]]}
During evaluation of In[2]:= {}
Out[2]= a
也许可以定义某种类型的语法结构,在计算之前阻止符号的创建

关于创建新符号时的求值阶段 我们可以看到,增量
$Line
发生在调用
MakeExpression
之前,而新的
Symbol
创建和为
InString
中的
变量赋值发生在调用
MakeExpression
之后:

In[1]:= ?f
InputForm[MakeExpression[ToExpression@InString[1], StandardForm]]

During evaluation of In[1]:= Information::notfound: Symbol f not found. >>

Out[2]//InputForm=
HoldComplete[Information["f", LongForm -> False]]
In[1]:= MakeExpression[My`boxes_,My`f_]/;!TrueQ[My`$InsideMakeExpression]:=Block[{My`$InsideMakeExpression=True},Print[$Line];Print[DownValues[InString][[All,1]]];Print[DownValues[In][[All,1]]];Print[Names["`*"]];MakeExpression[My`boxes,My`f]];
In[2]:= a
During evaluation of In[2]:= 2
During evaluation of In[2]:= {HoldPattern[InString[1]]}
During evaluation of In[2]:= {HoldPattern[In[1]]}
During evaluation of In[2]:= {}
Out[2]= a
关于和
$NewSymbol
通话时间,我们也可以这样说:

In[1]:= $NewSymbol:=Print["Names[\"`*\"]=",Names["`*"],"\nDownValues[InString]=",DownValues[InString][[All,1]],"\nDownValues[In]=",DownValues[In][[All,1]],"\nName: ",#1,"\tContext: ",#2]&
In[2]:= a
During evaluation of In[2]:= Names["`*"]={}
DownValues[InString]={HoldPattern[InString[1]]}
DownValues[In]={HoldPattern[In[1]]}
Name: a Context: Global`
Out[2]= a
$Pre
在对
中的
进行新分配后,以及在当前
$Context
中创建所有新的
符号后执行:

In[1]:= $Pre := (Print[Names["`*"]]; 
   Print[DownValues[In][[All, 1]]]; ##) &

In[2]:= a

During evaluation of In[2]:= {a}

During evaluation of In[2]:= {HoldPattern[In[1]],HoldPattern[In[2]]}

Out[2]= a
看来



结论是:在调用
$PreRead
MakeExpression
$NewSymbol
之后创建了新的
符号
,但在调用
$Pre

之前,您可以使用并更好地理解符号的创建时间。但从虚拟书中,符号是在
$Context
中创建的,而在
$Context
$ContextPath
中都找不到,关于编辑部分中的问题:不确定这是否是您的想法,但是在前端会话中,您可以使用
$PreRead
在解析阶段将符号保留为字符串。下面是一个可能的黑客:

symbolQ = StringMatchQ[#, RegularExpression["[a-zA-Z$][a-zA-Z$`0-9]*"]] &;

ClearAll[keepSymbolsAsStrings];
SetAttributes[keepSymbolsAsStrings, HoldAllComplete];

$PreRead  = # //. RowBox[{"keepSymbolsAsStrings", rest___}] :>
 RowBox[{"keepSymbolsAsStrings", 
   Sequence @@ ({rest} //. x_String?symbolQ :>
       With[{context = Quiet[Context[x]]},            
        StringJoin["\"", x, "\""] /; 
         Head[context] === Context])}] &;
仅当符号尚不存在时,才会将其转换为字符串(通过
上下文[symbol\u string\u name]
进行检查)。比如说

In[4]:= keepSymbolsAsStrings[a+b*Sin[c]]//FullForm

Out[4]//FullForm= keepSymbolsAsStrings[Plus["a",Times["b",Sin["c"]]]]
首先定义
keepSymbolsAsStrings
非常重要,以便创建此符号。这使得它重新进入:

In[6]:= keepSymbolsAsStrings[a+b*Sin[c]*keepSymbolsAsStrings[d+e*Sin[f]]]//FullForm

Out[6]//FullForm= 
  keepSymbolsAsStrings[Plus["a",Times["b",Sin["c"],
  keepSymbolsAsStrings[Plus["d",Times["e",Sin["f"]]]]]]]
现在,您可以在代码解析后以自己喜欢的方式处理这些符号(保留为字符串)。您也可以使用不同的
symbolQ
函数-为了举例,我只使用了一个简单的函数

但这对软件包不起作用。我不认为有一种简单的方法可以对包执行此操作。一种简单的方法是动态地重新定义
需求
,以类似于预处理阶段的方式在字符串级别修改源代码,并对修改后的源代码有效地调用
需求
。但是字符串级别的源代码修改通常是脆弱的

编辑

上述代码有一个缺陷,即很难区分哪些字符串是字符串,哪些是由上述函数转换的符号。通过将
clearl[keepSymbolsAsStrings]
更改为
clearl[keepSymbolsAsStrings,symbol]
StringJoin[“\”,x,“\”]
by
RowBox[{“symbol”,“[”,StringJoin[“\”,x,“\”,“]),可以修改上述代码
跟踪结果表达式中的哪些字符串对应于转换后的符号

编辑2

以下是修改后的代码,它基于
MakeExpression
而不是@Alexey建议的
$PreRead

symbolQ =  StringMatchQ[#, RegularExpression["[a-zA-Z$][a-zA-Z$0-9`]*"]] &;

ClearAll[keepSymbolsAsStrings, symbol];
SetAttributes[keepSymbolsAsStrings, HoldAllComplete];

Module[{tried},
 MakeExpression[RowBox[{"keepSymbolsAsStrings", rest___}], form_] :=
  Block[{tried = True},
    MakeExpression[
       RowBox[{"keepSymbolsAsStrings", 
         Sequence @@ ({rest} //. x_String?symbolQ :>
            With[{context = Quiet[Context[x]]},            
             RowBox[{"symbol", "[", StringJoin["\"", x, "\""], "]"}] /;
             Head[context] === Context])}], form]
  ] /;!TrueQ[tried]
]
我们需要Todd Gayley的例子来打破
MakeExpression
定义中的无限递归。以下是例子:

In[7]:= keepSymbolsAsStrings[a+b*Sin[c]]//FullForm

Out[7]//FullForm= keepSymbolsAsStrings[Plus[symbol["a"],Times[symbol["b"],Sin[symbol["c"]]]]]

In[8]:= keepSymbolsAsStrings[a+b*Sin[c]*keepSymbolsAsStrings[d+e*Sin[f]]]//FullForm

Out[8]//FullForm=  keepSymbolsAsStrings[Plus[symbol["a"],Times[symbol["b"],Sin[symbol["c"]],
keepSymbolsAsStrings[Plus[symbol["d"],Times[symbol["e"],Sin[symbol["f"]]]]]]]]

此方法更简洁,因为最终用户仍然可以使用
$PreRead

我认为您对输入解析为表达式时创建符号的基本理解是正确的


微妙之处在于,行开头的
(以及
)专门进行解析,以允许字符串不需要引号。(这里的隐式字符串是模式,如
*Min*
用于
以及
的文件名)

执行DownValues[In]//首先//FullForm我看到RuleDelayed[HoldPattern[In[1]],信息[“f”,规则[LongForm,False]]].@Sasha你是对的,我错过了
FullForm
。这意味着在真正意义上,符号
f
并不像我之前所想的那样在
的定义中使用。但是你能评论一下我对符号创造的理解(在问题的第一段描述)对吗?谢谢你这个聪明的解决方案!但可能是新定义的方法