Accidental shadowing and `Removed[symbol]`

后端 未结 2 615
我在风中等你
我在风中等你 2021-01-14 19:06

If you evaluate the following code twice, results will be different. Can anyone explain what\'s going on?

findHull[points_] := Module[{},
   Needs[\"Computat         


        
相关标签:
2条回答
  • 2021-01-14 19:46

    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.

    0 讨论(0)
  • 2021-01-14 20:08

    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

    0 讨论(0)
提交回复
热议问题