為什麼Mathematica中無法Manipulate一個先前定義的變數中的參數?
比如我想Manipulate如下代碼的antiorz,直接寫該表達式就可以Manipulate,但是用另一個變數表示的話就不能Manipulate了,這是為什麼呢?
結果如下:
Orzzz = orz*orz*antiorz;
Manipulate[Plot[orz*orz*antiorz, {orz, -1, 1}], {antiorz, -1, 1}]
Manipulate[ Plot[Orzzz, {orz, -1, 1}], {antiorz, -1, 1}]
有點複雜,我不知道怎麼說……總之,Manipulate裡邊的那個 antiorz 不是真正的 antiorz ,而是 antiorz$2333 之類的東西。Manipulate 的幫助里提到:
- Manipulate generates a DynamicModule object, with the variables u, v, etc. specified as local.
怎麼 specified as local ?再看 DynamicModule 的幫助:
- DynamicModule first gives unique names to local variables in expr, just like Module, then evaluates the resulting expression, and then returns a version of this wrapped in DynamicModule.
也就是說,這裡處理局部變數的辦法跟 Module 差不多。那 Module 是怎麼乾的呢?它先給這個局部變數一個獨一無二的名字,比如說你本來管這個變數叫 x ,Mathematica 就給它起一個名字叫 x$233 ,或者 x$445 ,總之這個名字不會與之前用過的任何名字重複;然後,在 Module 里每次遇到x,Mathematica都會把它理解成 x$233 。
但是,如果,比如說,定義一個 y=x ,這時計算 Module[{x},y] ,結果會是這樣:
這是因為這裡定義的 y 是等於全局變數 x ,而不是局部變數 x$233 。
DynamicModule 比 Module 要複雜一些,但道理也一樣。在計算
Manipulate[Plot[orz*orz*antiorz, {orz, -1, 1}], {antiorz, -1, 1}]
的時候,這裡邊的兩個 antiorz 都不是真正的 antiorz ,而是 antiorz$2333 之類的東西。而在計算
Manipulate[ Plot[Orzzz, {orz, -1, 1}], {antiorz, -1, 1}]
的時候,後面那個 antiorz 其實是 antiorz$2333 之類的東西,而 Orzzz 裡邊的 antiorz 卻是真正的 antiorz ,所以就是那樣的結果……
=====
其實,這裡還涉及到一個 dynamic scoping 和 lexical scoping 的問題。關於 dynamic scoping 和 lexical scoping 的介紹,可以看王垠老師的文章《Lisp 已死,Lisp 萬歲!》。Mathematica是比較少見的同時支持 dynamic scoping 和 lexical scoping 的語言:同樣是定義局部變數,用 Block 就是 dynamic scoping ,用 Module 就是 lexical scoping 。例如:
假如 Manipulate 也是 dynamic scoping 的話,你那樣寫就不會有問題了。可以修改成
Clear[Orzzz]
Orzzz[antiorz_]:=orz*orz*antiorz;
Manipulate[Plot[Orzzz[antiorz],{orz,-1,1}],{antiorz,-1,1}]
這樣在 Manipulate 運行過程中,Orzzz 會隨著 antiorz 的值變化而變化。
因為
=
在Mathematica中是立刻賦值(計算值以後就和他們沒啥關係了……),而
:=
是懶惰賦值,就是每次需要計算值的時候都回去算一遍。
a = 0
b = a
a = 1
b (* is 0 *)
而
a = 0
b := a
a = 1
b (* is a, aka, 1 *)
==========UPDATE HERE==========
(* 感謝 @AlephAlpha 的提醒 *)才發現是Manipulate啊……因為Manipulate會localize所有variable(包括這裡的antiorz),所以你「全局的」antiorz是什麼值和Manipulate沒有任何關係。所以你才能寫類似下面的語句b := wtf
Manipulate[a * b, {a, -1, 1}, {b, -1, 1}]
b (* is wtf, after some "b" was dragged to somewhere else *)
如果想使用全局變數,可以設置LocalizeVariables -&> False
ref: Mathematica/Function Navigator/ ref/Manipulate推薦閱讀:
TAG:數學 | 編程 | 數學軟體 | WolframMathematica | WolframLanguage |