2011-12-15 23 views
7

傳遞參數這個問題上通過的由M個參考對象(我的一個相關的問題是在這裏simple question on passing data between functions使用結構參照

當我試圖找到一種方法,通過引用傳遞的東西沒有使用Unevaluted[]HoldFirst[],我誤以爲這種方法,儘管我不明白它是如何工作的以及使用它的任何隱藏風險,但它看起來對我來說確實很好。所以我想在這裏向專家展示它,並詢問他們是否認爲它可以安全地使用(我有非常大的演示,並需要將參數打包到許多不同結構中以幫助管理它們,這就是我如何找到它的原因方法,而我正在嘗試的東西)。

這裏的方法:首先,我們知道,一個人不能寫:要更新「P」在上面的是改變調用成爲

Remove[p] 
foo[p_] := Module[{u}, 
    u = Table[99, {10}]; 
    p = u 
    ]; 

p = 0; 
foo[p]; 

一種方式

foo[[email protected]]; 

或者通過定義foo[]HoldFirst

但這裏是我發現的方式,它不通過引用傳遞,沒有任一:

我把所有的參數在結構(我現在做到這一點無論如何),並通過結構和然後一個可以更新結構的領域內foo[]和更新將在從函數調用返回的途中反映:

Remove[parms] 
foo[parms_] := Module[{u}, 
    u = Table[99, {10}]; 
    parms["p"] = u 
    ]; 

parms["p"] = 0; 
foo[parms]; 

現在,parms["p"]包含在新的列表{99, 99, 99, 99, 99, 99, 99, 99, 99, 99}

小號o,parmsfoo[]內被覆蓋/更新,我不必告訴M通過parms作爲參考!

我在我的程序中試過這個,我沒有看到奇怪的副作用。 CDF已更新,沒有錯誤。我不知道這是如何工作的,可能是M將parms中的所有字段視爲全局?

但無論是哪種情況,只要它提供了將我的許多參數打包到結構中的方法,我就很高興,同時我可以在結構中更新函數內部。

但我的問題是:你看到這個方法的一個主要問題?它如何在內部工作?我的意思是M如何在沒有我的情況下處理這個事情HoldFirstUnevaluated?我知道我現在失去了像以前一樣進行參數檢查的能力,但是我不能擁有我想要的一切。正如我之前所說的,M需要一個真正的內置結構作爲語言的一部分並將其集成到其中。但是這是另一次談論。

順便說一句,迄今爲止我看到的最好的結構仿真是由Leonid Shifrin在本帖末尾貼出的這個結果here,但不幸的是我不能在演示中使用它,因爲它使用演示中不允許的符號CDF。

感謝

更新: 順便說一句,這下面是什麼,我認爲中號如何處理這個。這只是我的猜測:我認爲param是某種查找表,它的字段只是用作索引(可能是一個哈希表?)然後param["p1"]將包含地址(不是值)在param["p1"]的實際值所在的堆的位置。

事情是這樣的:

enter image description here

所以,路過param時,則函數foo[],打字param["p1"]=u裏面的時候就會造成當前內存指向"p1"被釋放出來,然後從堆中分配新內存,並在其中複製u的值。

所以,回來後,這就是爲什麼我們看到param["p1"]的內容發生了變化。但實際改變的是內存的內容是由param["p1"]表示的地址指向的。 (有一個名稱,它是"p1",和地址字段,它指向該名稱"p1"表示內容)

但是那麼這意味着,該地址本身,這"p1"表示發生了變化,但查找名稱本身(即「p1」)沒有改變。

因此,由於名稱本身沒有改變,所以不需要使用HoldFirst,即使這個名稱所代表的數據被修改了嗎?

更新:

有這種方法的一個小故障,但它不是一個大問題,解決它:通過使用該索引對象方法的事情時,事實證明,缺一不可修改對象的一部分。例如,下面這不起作用:以上

foo[param_] := Module[{}, 
    param["u"][[3]] = 99 (*trying to update PART of u *) 
    ]; 

param["u"] = Table[0, {5}]; 
foo[param]; 

給出了錯誤

Set::setps: "param[u] in the part assignment is not a symbol" 

但解決方法很簡單。做出一個要更新的一部分整場的本地副本,然後更新本地副本的(部分),然後寫拷貝回場,這樣

foo[param_] := Module[{u = param["u"]}, (* copy the whole field *) 
    u[[3]] = 99; (*update local copy *) 
    param["u"] = u (*now update the field, ok *) 
    ]; 

param["u"] = Table[0, {5}]; 
foo[param]; 

嘛。如果可以更新部分領域,情況會更好,因此不需要「特殊」處理。但至少周圍的工作並沒有那麼糟糕。

更新 爲了完整起見,我想我提到了另一個有關使用索引對象和解決方法的細小問題。

我寫

param[u] = {1, 2, 3} 
param[u][[1 ;; -1]] 

預期它返回{1,2,3}

然後我發現我可以使用[email protected]而不是param[u],這真的很有幫助,因爲太多固定的支架開始讓我頭疼。

但是當我輸入

[email protected][[1 ;; -1]] 

期望像以前一樣得到相同的答案,事實並非如此。 (我想我知道爲什麼,運營商優先級問題,但那不是現在這一點),只是想說解決方法很簡單,可以使用param[u][[1 ;; -1]]或使用([email protected])[[1 ;; -1]]

我喜歡([email protected])[[1 ;; -1]]更多,所以這就是我現在用來訪問索引對象內的列表。

符號[email protected]與我可以達到的標準記錄表示法是param.u,因此我現在對索引對象感到高興,它似乎工作得很好。只需要注意幾件小事。

+0

這個問題有很多。你有沒有具體的事情要做? – 2011-12-15 07:04:25

回答

5

我不會回答低級數據結構的問題,因爲我根本沒有資格這樣做。

您正在創建"indexed objects"並使用不可變字符串作爲索引。一般來說,我認爲這些與散列表相似。

以你的代碼示例,讓我們用一個唯一的名稱爲foo的參數來移除可能的歧義:

Remove[parms, foo] 

foo[thing_] := 
    Module[{u}, 
    u = Table[99, {10}]; 
    thing["p"] = u 
    ]; 

parms["p"] = 0; 
foo[parms]; 

parms["p"] 

DownValues[parms] 
{HoldPattern[parms["p"]] :> {99, 99, 99, 99, 99, 99, 99, 99, 99, 99}}

這說明數據是如何存儲在高水平數學方面結構。

parms是一個全局符號。正如你所觀察到的,它可以安全地「通過」而不會發生任何事情,因爲它只是一個沒有OwnValues的符號,在評估時不會觸發任何事情。這與編寫/評估foo本身完全相同。

發生在foo[thing_] := ...的替換類似於With。如果我們寫:

With[{thing = parms}, thing[x]] 

thingthing[x]被替換parmsthing[x]評析。同樣,在上面的代碼中,我們在thing["p"]Set評估之前得到parms["p"] = u。那時,SetHoldFirst屬性接管了,並且你得到你想要的。

由於您使用不可變字符串作爲您的索引,它不會有變化的危險。只要您知道如何處理非本地化符號(例如parms),那麼我在使用此方法時也看不到新的危險。