如果您评估以下代码两次,结果将会不同。任何人都可以解释发生了什么?意外阴影和`删除[符号]`
findHull[points_] := Module[{},
Needs["ComputationalGeometry`"];
ConvexHull[points]
];
findHull[RandomReal[1, {10, 2}]];
Remove["Global`ConvexHull"];
findHull[RandomReal[1, {10, 2}]]
如果您评估以下代码两次,结果将会不同。任何人都可以解释发生了什么?意外阴影和`删除[符号]`
findHull[points_] := Module[{},
Needs["ComputationalGeometry`"];
ConvexHull[points]
];
findHull[RandomReal[1, {10, 2}]];
Remove["Global`ConvexHull"];
findHull[RandomReal[1, {10, 2}]]
的问题是,即使模块不评估,直到你打电话findHull
,这些符号都解决了,当你定义findHull
(即:为findHull
新downvalue存储在符号,而不是文本的条款)。 这意味着在第一轮中,ConvexHull
解析为Global`ConvexHull
,因为Needs
未被评估。 在第二轮中,ComputationalGeometry
在$ContextPath
上,所以ConvexHull
按照您的意愿解决。
如果您确实无法承受预先加载ComputationalGeometry
,请参考ConvexHull
的全名:ComputationalGeometry`ConvexHull
。另请参阅this related answer。
HTH
不是问题的直接答案,但对评论太大了。作为另一种选择,延迟符号解析直到运行时的一般方法是使用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用一个新定义替换旧定义的事实,如果它可以确定这些模式是相同的 - 就像在这种情况下那样。
自我重新定义技巧有用的其他实例是,例如,一个函数调用会导致一些我们想要缓存的昂贵计算的情况,但我们不确定该函数是否会被调用。然后,这样的构造允许在第一次调用函数时自动缓存计算出的(比如符号)结果。
谢谢,有道理。我发现另一个上下文gotcha是函数内定义的函数包内的MyPackage被放入私人'而不是MyPackage'Private' – 2011-02-14 05:30:37
@Yaroslav。无法重现那一个 - 你记得使用Begin [“` Private `”]而不是Begin [“Private`”](因为如果你没有,那会导致你描述的行为)? – Janus 2011-02-14 05:57:50