意外阴影和`删除[符号]`

时间:2011-02-14 02:47:38

标签: wolfram-mathematica

如果您评估以下代码两次,结果将会有所不同。谁能解释一下发生了什么?

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

2 个答案:

答案 0 :(得分:6)

问题在于,即使未评估模块,直到您调用findHull,当您定义findHull时,符号也会被解析(即:findHull的新下值存储在符号的术语,而不是文本)。 这意味着在第一轮中,ConvexHull会解析为Global`ConvexHull,因为未评估Needs。 在第二轮中,ComputationalGeometry已在$ContextPath上,因此ConvexHull会按您的意图结算。

如果您真的无法忍受事先加载ComputationalGeometry,请使用ConvexHull的全名:ComputationalGeometry`ConvexHull。另请参阅this related answer

HTH

答案 1 :(得分: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的原始定义被内部定义替换,并且在加载所需的包并将其上下文放在{{1 }}。在这里,我们利用Mathematica将旧定义替换为新定义的事实,如果它可以确定模式是相同的 - 就像在这种情况下一样。

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