為什麼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 |