2011-02-14 93 views
3

如果您評估以下代碼兩次,結果將會不同。任何人都可以解釋發生了什麼?意外陰影和`刪除[符號]`

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

回答

6

的問題是,即使模塊不評估,直到你打電話findHull,這些符號都解決了,當你定義findHull(即:爲findHull新downvalue存儲在符號,而不是文本的條款)。 這意味着在第一輪中,ConvexHull解析爲Global`ConvexHull,因爲Needs未被評估。 在第二輪中,ComputationalGeometry$ContextPath上,所以ConvexHull按照您的意願解決。

如果您確實無法承受預先加載ComputationalGeometry,請參考ConvexHull的全名:ComputationalGeometry`ConvexHull。另請參閱this related answer

HTH

+0

謝謝,有道理。我發現另一個上下文gotcha是函數內定義的函數包內的MyPackage被放入私人'而不是MyPackage'Private' – 2011-02-14 05:30:37

+0

@Yaroslav。無法重現那一個 - 你記得使用Begin [「` Private `」]而不是Begin [「Private`」](因爲如果你沒有,那會導致你描述的行爲)? – Janus 2011-02-14 05:57:50

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的原始定義被內部替換,並且在加載所需的包並將其上下文放置在$ContextPath後已經發生。在這裏,我們利用Mathematica用一個新定義替換舊定義的事實,如果它可以確定這些模式是相同的 - 就像在這種情況下那樣。

自我重新定義技巧有用的其他實例是,例如,一個函數調用會導致一些我們想要緩存的昂貴計算的情況,但我們不確定該函數是否會被調用。然後,這樣的構造允許在第一次調用函數時自動緩存計算出的(比如符號)結果。