我认为这是一个非常深入和有价值的问题,根据投票数来看,我并不是唯一这样想的。如果我们在语言级别上完全支持了这个特性,那么这将给我们一种全新的方式来操作作用域和封装,通常会允许更清晰的代码和更好的信息隐藏。这类似于Python中的from module-name import name1,name2,...
。
也许和许多人一样,我尝试过多种方法,但它们都似乎脆弱且不完整。最糟糕的情况是对于包,我没有好的解决方案。对于在前端进行交互式工作,这里有一个可能可以接受的解决方案。首先定义一个通用的宏来进行文字替换:
ClearAll[withImported];
SetAttributes[withImported, HoldAll];
withImported[importingRules : {(_Symbol -> _String) ..}, code_] :=
With @@ Join[
Hold[importingRules] /.
(name_Symbol -> context_String) :>
With[{eval =
Block[{$ContextPath = Append[$ContextPath, context]},
ToExpression[context <> ToString[Unevaluated@name]]
]},
Set[name, eval] /; True],
Hold[code]];
withImported[importingRules : {({__Symbol} -> _String) ..}, code_] :=
Reverse[Hold @@ Flatten[Unevaluated[importingRules] /.
({syms__Symbol} -> s_String) :> Thread[s :> {syms}]], {2}] /.
RuleDelayed -> Rule /.
Hold[expandedRules : ((_Symbol -> _String) ..)] :>
withImported[{expandedRules}, code];
接下来,创建一个函数,其中包括你喜欢的快捷方式,例如:
shortcutF =
Function[code,
withImported[
{
{PackedArrayQ, ToPackedArray, FromPackedArray} -> "Developer`",
{InheritedBlock, WithLocalSettings} -> "Internal`"
},
code
],
HoldAll];
现在您可以将代码包裹在shortcutF
中并开始使用简称。目前为止,这也适用于包,但是您将不得不将所有代码(或至少包含快捷方式的那些部分)都包装在shortcutF
中,这不是很方便。为了进一步方便,您可以将上述函数分配给$Pre
:
$Pre = shortcutF
这里是一些使用示例:
In[31]:=
WithLocalSettings[Null,Abort[],Print["Cleanup"]]
During evaluation of In[31]:= Cleanup
Out[31]= $Aborted[]
In[32]:= PackedArrayQ[Range[10]]
Out[32]= True
In[33]:= PackedArrayQ@FromPackedArray[Range[10]]
Out[33]= False
由于With
在内部使用,因此在执行代码之前,您的快捷符号将被完全限定的符号名称替换。
这是我能做到的最好程度,但这个特性似乎特别需要语言本身的支持。
Unprotect
或类似的工具,也可以使用Context[symbol] = "context`"
重新定义System
或Internal
符号的上下文。然而,这将从其原始上下文中移除该符号,这是不可接受的。有没有办法为一个符号分配两个不同的上下文? - Mr.Wizard