意外的阴影和“已删除[符号]”
如果您对以下代码求值两次,结果将会不同。谁能解释一下发生了什么事吗?
findHull[points_] := Module[{},
Needs["ComputationalGeometry`"];
ConvexHull[points]
];
findHull[RandomReal[1, {10, 2}]];
Remove["Global`ConvexHull"];
findHull[RandomReal[1, {10, 2}]]
If you evaluate the following code twice, results will be different. Can anyone explain what's going on?
findHull[points_] := Module[{},
Needs["ComputationalGeometry`"];
ConvexHull[points]
];
findHull[RandomReal[1, {10, 2}]];
Remove["Global`ConvexHull"];
findHull[RandomReal[1, {10, 2}]]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题是,即使在调用
findHull
之前不会评估模块,但当您定义findHull
时,符号就会解析(即:findHull< 的新下值) /code> 以符号形式存储,而不是文本)。
这意味着在第一轮期间,
ConvexHull
解析为Global`ConvexHull
,因为未评估Needs
。在第二轮中,
ComputationalGeometry
位于$ContextPath
上,因此ConvexHull
按照您的预期进行解析。如果您实在无法忍受预先加载
ComputationalGeometry
,请参考ConvexHull
的全名:ComputationalGeometry`ConvexHull
。另请参阅此相关答案。华泰
The problem is that even though the module is not evaluated untill you call
findHull
, the symbols are resolved when you definefindHull
(i.e.: The new downvalue forfindHull
is stored in terms of symbols, not text).This means that during the first round,
ConvexHull
resolves toGlobal`ConvexHull
because theNeeds
is not evaluated.During the second round,
ComputationalGeometry
is on$ContextPath
and soConvexHull
resolves as you intended.If you really cannot bear to load
ComputationalGeometry
beforehand, just refer toConvexHull
by its full name:ComputationalGeometry`ConvexHull
. See also this related answer.HTH
不是问题的直接答案,但对于评论来说有点太大了。作为另一种选择,将符号解析延迟到运行时的一般方法是使用
Symbol["your-symbol-name"]
。在您的情况下,您可以将定义右侧的ConvexHull
替换为Symbol["ConvexHull"]
:不过,此解决方案不是很优雅,因为
Symbol[ "ConvexHull"]
每次都会重新执行。如果您使用$ContextPath
进行重要操作,这也可能容易出错。这是一个修改后的版本,结合了一个通常有用的自我重定义技巧,我在类似的情况下使用它:例如,
发生的情况是,第一次调用该函数时,使用
Module
被内部的替换,并且在加载所需的包并将其上下文放置在$ContextPath
上之后就已经发生了。在这里,我们利用了这样一个事实:如果 Mathematica 可以确定模式相同,则它会用新定义替换旧定义 - 就像在这种情况下一样。自重定义技巧有用的其他情况是,例如,函数调用导致一些昂贵的计算,我们想要缓存这些计算,但我们不确定该函数是否会被调用。然后,这样的构造允许在第一次调用该函数时自动缓存计算的(例如,象征性的)结果。
Not a direct answer to the question, but a bit too large for a comment. As another alternative, a general way to delay the symbol parsing until run-time is to use
Symbol["your-symbol-name"]
. In your case, you can replaceConvexHull
on the r.h.s. of your definition bySymbol["ConvexHull"]
:This solution is not very elegant though, since
Symbol["ConvexHull"]
will be executed every time afresh. This can also be somewhat error-prone, if you do non-trivial manipulations with$ContextPath
. Here is a modified version, combined with a generally useful trick with self-redefinition, that I use in similar cases:For example,
What happens is that the first time the function is called, the original definition with
Module
gets replaced by the inner one, and that happens already after the needed package is loaded and its context placed on the$ContextPath
. Here we exploit the fact that Mathematica replaces an old definition with a new one if it can determine that the patterns are the same - as it can in such cases.Other instances when self-redefinition trick is useful are cases when, for example, a function call results in some expensive computation, which we want to cache, but we are not sure whether or not the function will be called at all. Then, such construct allows to cache the computed (say, symbolically) result automatically upon the first call to the function.