2011-02-14 94 views
3

如果您评估以下代码两次,结果将会不同。任何人都可以解释发生了什么?意外阴影和`删除[符号]`

findHull[points_] := Module[{}, 
    Needs["ComputationalGeometry`"]; 
    ConvexHull[points] 
    ]; 
findHull[RandomReal[1, {10, 2}]]; 
Remove["Global`ConvexHull"]; 
findHull[RandomReal[1, {10, 2}]] 

回答

6

的问题是,即使模块不评估,直到你打电话findHull,这些符号都解决了,当你定义findHull(即:为findHull新downvalue存储在符号,而不是文本的条款)。 这意味着在第一轮中,ConvexHull解析为Global`ConvexHull,因为Needs未被评估。 在第二轮中,ComputationalGeometry$ContextPath上,所以ConvexHull按照您的意愿解决。

如果您确实无法承受预先加载ComputationalGeometry,请参考ConvexHull的全名:ComputationalGeometry`ConvexHull。另请参阅this related answer

HTH

+0

谢谢,有道理。我发现另一个上下文gotcha是函数内定义的函数包内的MyPackage被放入私人'而不是MyPackage'Private' – 2011-02-14 05:30:37

+0

@Yaroslav。无法重现那一个 - 你记得使用Begin [“` Private `”]而不是Begin [“Private`”](因为如果你没有,那会导致你描述的行为)? – Janus 2011-02-14 05:57:50

2

不是问题的直接答案,但对评论太大了。作为另一种选择,延迟符号解析直到运行时的一般方法是使用Symbol["your-symbol-name"]。在你的情况下,你可以在r.h.s.上替换ConvexHull。通过Symbol["ConvexHull"]您定义的:

findHull[points_] := 
Module[{}, 
    Needs["ComputationalGeometry`"]; 
    Symbol["ConvexHull"][points]]; 

该解决方案是不是很优雅不过,因为Symbol["ConvexHull"]每次都会重新执行。如果您使用$ContextPath进行非平凡的操作,这也可能有点容易出错。下面是修改后的版本,与自我的重新定义一个通常有用的技巧相结合,我在类似的情况下使用:

Clear[findHull]; 
findHull[points_] := 
Module[{}, 
    Needs["ComputationalGeometry`"]; 
    With[{ch = Symbol["ConvexHull"]}, 
    findHull[pts_] := ch[pts]; 
    findHull[points]]]; 

例如,

findHull[RandomReal[1, {10, 2}]] 

{4, 10, 9, 1, 6, 2, 5} 

什么情况是,第一次函数被调用时,Module的原始定义被内部替换,并且在加载所需的包并将其上下文放置在$ContextPath后已经发生。在这里,我们利用Mathematica用一个新定义替换旧定义的事实,如果它可以确定这些模式是相同的 - 就像在这种情况下那样。

自我重新定义技巧有用的其他实例是,例如,一个函数调用会导致一些我们想要缓存的昂贵计算的情况,但我们不确定该函数是否会被调用。然后,这样的构造允许在第一次调用函数时自动缓存计算出的(比如符号)结果。