意外的阴影和“已删除[符号]”

发布于 2024-10-17 01:13:19 字数 259 浏览 0 评论 0原文

如果您对以下代码求值两次,结果将会不同。谁能解释一下发生了什么事吗?

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ι不睡觉的鱼゛ 2024-10-24 01:13:19

问题是,即使在调用 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 define findHull (i.e.: The new downvalue for findHull is stored in terms of symbols, not text).
This means that during the first round, ConvexHull resolves to Global`ConvexHull because the Needs is not evaluated.
During the second round, ComputationalGeometry is on $ContextPath and so ConvexHull resolves as you intended.

If you really cannot bear to load ComputationalGeometry beforehand, just refer to ConvexHull by its full name: ComputationalGeometry`ConvexHull. See also this related answer.

HTH

要走干脆点 2024-10-24 01:13:19

不是问题的直接答案,但对于评论来说有点太大了。作为另一种选择,将符号解析延迟到运行时的一般方法是使用 Symbol["your-symbol-name"]。在您的情况下,您可以将定义右侧的 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 可以确定模式相同,则它会用新定义替换旧定义 - 就像在这种情况下一样。

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

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 replace ConvexHull on the r.h.s. of your definition by Symbol["ConvexHull"]:

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

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:

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

For example,

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文