2016-11-18 21 views
0

我是否正確理解了在多數調度語言中(多數?某些?),每個方法都會在程序執行的某個時間點被添加到函數中。功能在多個調度系統中是否可變?

那麼我可以得出結論:多派遣作爲一個功能強制功能是可變的嗎?

是否有多種調度語言,其中所有方法一起附加到(通用)函數(加載時?),以便不可能在不同時間點看到不同狀態下的函數?

+1

也許簡單的答案是,在Julia中,每個* generic函數*都是函數的集合,對於不同的簽名,每個簽名都不可變。大多數Julia * generic函數*調用在編譯時使用類型推斷系統選擇要調用的特定函數簽名。如果你想詳細說明你關心的*無狀態編程*功能,這將有助於解決它們。 –

+1

@DanGetz,我實際上並不關心可變性 - 我只是想更好地理解multimethods。我現在相應地編輯了我的問題。 – Aivar

回答

5

在程序執行的某個時間點。

在通用Lisp中,當方法定義被執行時,方法被添加/替換 - 對於編譯系統,這通常是在編譯代碼的加載時 - 不一定在程序執行期間。

請記住,Common Lisp有一個對象系統(CLOS,Common Lisp對象系統),它由其行爲定義。它與語言語言擴展稍有不同。

Common Lisp允許運行時修改對象系統。例如還可以添加/刪除/替換方法。

Common Lisp也可能將合併爲多於一種適用方法爲有效方法,然後執行。典型示例:所有適用的:before方法和最具體適用的主要方法將合併爲一個有效方法

在某些實現中存在對CLOS的擴展,其中密封是針對更改的通用函數。

欲瞭解目標系統想法的更長時間的處理,請參閱:Richard P. Gabriel的The Structure of a Programming Language Revolution

2

從對這個(重點煤礦)一個很好的部分優秀「Getting started with Julia」書複述:

我們已經看到了函數本身定義爲通用的,也就是說,它們可以用於不同他們的論點的類型。 每次使用新類型的參數調用編譯器時,編譯器都會生成一個單獨版本的函數。具體的參數類型組合函數的具體版本在Julia中稱爲方法要定義函數的新方法(也稱爲重載),只需使用相同的函數名稱,但使用不同的簽名,即使用不同的參數類型

所有方法的列表都存儲在函數本身的虛擬方法表(vtable)中;方法不屬於特定的類型。當一個函數被調用時,Julia將在運行時對該表進行查找,以根據其所有參數的類型查找應該調用哪個具體方法;這是Julia的多重調度機制,既不是Python,也不是C++或Fortran實現的機制。它允許打開擴展,在這些擴展中,普通的面向對象的代碼會迫使你更改現有類的類或子類,從而改變你的庫。請注意,只有位置參數纔會考慮多個分派,而不是關鍵字參數。

對於這些不同的方法中的每一種,生成針對處理器指令集的專用低級代碼。 與面向對象(OO)語言相反,vtable存儲在函數中,而不是存儲在類型(或類)中。在OO語言中,在單個對象object.method()上調用一個方法,該方法通常稱爲單個調度。在Julia中,可以說一個函數屬於多種類型,或者一個函數是專用的或者爲不同類型重載的。 Julia能夠將像高級動態語言一樣讀取的代碼編譯爲像C一樣執行的機器代碼,這種能力幾乎完全來自於它能夠執行多次調度。

所以,我明白這一點(我可能是錯的)的方式是:

  • 通用功能需要在會議上界定之前,你可以用它
  • 的明確定義的方法具體參數被添加到函數的多派遣查找表中,在它們被定義的地方。
  • 無論何時使用特定參數調用某個顯式定義的方法不存在的函數,都會編譯這些參數的具體版本並將其添加到vtable中。 (但是,如果您在該函數名稱上運行methods(),則不會顯示爲明確的方法)
  • 第一次調用此類函數將導致一些編譯開銷;但是,後續調用將使用現有的編譯版本*。

我不會說這使得功能mutable雖然,這是一個完全不同的問題。您可以使用函數'handle'上的isimmutable()函數來確認自己是不可變的。


*我知道模塊可以預編譯,但我不能完全肯定,如果這些對即時編譯的版本以任何形式保存會話之間 - 評論歡迎:)

2

如果僅用於調試,則動態性可能是應用程序中真正的資產。試圖阻止稍後更新函數,重新定義等可能有點短視。但是如果你確定你想要靜態分派,你可以定義你自己的通用函數類,這要歸功於MOP,元對象協議,它不是標準的一部分,但仍然在很大程度上得到了支持。這就是Inlined-Generic-Function庫所提供的(這是可能的,因爲CLOS對擴展開放)。

2

Common Lisp中,可以讀取從說明書的以下內容:

7.6.1 Introduction to Generic Functions

defgeneric形式進行評價時,以下三種操作之一被取(由於ensure-generic-function):

  • 如果給定名稱的泛型函數已經存在,則修改現有的泛型函數對象。添加由當前defgeneric表單指定的方法,並刪除現有通用函數中由前一個defgeneric表單定義的任何方法。通過當前的defgeneric形式添加的方法可以代替由defmethod,defclass,define-conditiondefstruct定義的方法。泛型函數中沒有其他方法受到影響或替換。
  • 如果給定的名稱命名爲普通函數,宏或特殊運算符,則會發出錯誤信號。
  • 否則,使用defgeneric表單中方法定義指定的方法創建泛型函數。

7.6.2 Introduction to Methods

當一個方法定義形式進行評估,創建一個方法對象和四個操作之一被取:

  • 如果給定的一般功能名稱已經存在,並且如果一個方法對象已經存在,並且與參數專用程序和限定符上的新方法對象一致,則新方法對象將替換舊方法對象。有關參數專用因子和限定符與另一種方法一致的定義,請參見第7.6.3節(參數專用程序和限定符的一致性)。
  • 如果給定名稱的泛型函數已經存在,並且如果沒有方法對象與參數專用程序和限定符上的新方法對象一致,則會修改現有的泛型函數對象以包含新的方法對象。
  • 如果給定的名稱命名爲普通函數,宏或特殊運算符,則會發出錯誤信號。
  • 否則,使用由方法定義窗體指定的方法創建泛型函數。

ensure-generic-function定義:

如果函數名指定具有爲:lambda-list參數不同的值的通用功能,並且新的值是一致的與所有現有的拉姆達名單方法或沒有方法,值改變;否則會發出錯誤信號。

如果函數名指定了一個具有:generic-function-class參數的不同值的泛型函數,並且新的泛型函數類與舊版兼容,則調用change-class來更改泛型函數的類;否則會發出錯誤信號。

如果函數名稱指定的參數:method-class具有不同值的泛型函數,則該值會更改,但任何現有方法都不會更改。

您還有add-methodremove-method

如您所見,通用函數在defmethod定義之間,甚至在defgeneric定義之間保留其標識。通用函數在Common Lisp中是可變的。


在朱莉婭,你可以閱讀從文檔以下內容:

Defining Methods

要使用多種方法定義一個函數,一個簡單的定義函數多次,不同數量和參數類型。函數的第一個方法定義創建函數對象,隨後的方法定義將新方法添加到現有函數對象。

正如您所看到的,函數對象在Julia中是可變的。


這對所有其他多種調度語言沒有任何意義。您現在可以創建多種派遣語言,只是爲了表明您可以通過不變的方式來完成這項工作。添加方法會返回一個類似於前一個函數但添加了方法的新函數。或者是在編譯時靜態生成函數的語言,因此無法以任何方式在運行時更改它,甚至不能添加或刪除方法。

相關問題