2017-06-19 61 views
4

考慮這個程序,我在參數列表中構造一個數組。雖然有這麼接受一個數組的簽名,這個調用接受列表中的一個:Perl 6的多派遣如何決定使用哪個例程?

foo([ 1, 2, 3 ]); 

multi foo (Array @array) { put "Called Array @ version" } 
multi foo (Array $array) { put "Called Array \$ version" } 
multi foo (List $list) { put "Called List version" } 
multi foo (Range $range) { put "Called Range version" } 

我得到的輸出從一個意想不到的例行:

Called Array $ version 

如果我取消,其他簽名,那一個被稱爲:

Called List version 

爲什麼它不叫(Array @array)版本?調度員如何做出決定(以及它在哪裏記錄)?

+1

cf'say( - > Array @ {})。signature.params [0]。輸入' – Christoph

+0

@briandfoy我已經刪除了關於逆轉(減少噪音)的評論。隨意刪除您的確認評論。稍後我會刪除這一個。 :) – raiph

+0

briandfoy您還沒有接受答案。我願意加倍努力。我想我完全解決了「爲什麼不叫...?」。我想我完全解決了「調度員如何做出決定?」因爲它與你的具體例子有關。我認爲@斯萊德的回答更廣泛地解決了這個問題。但你寫道:「這並不能解釋我所表現出的行爲。」根據我對他們的回答的評論,我認爲它的確如此。我可以擴大我的答案,「它在哪裏記錄?」通過鏈接到對應斯萊德的答案的文檔。我很感謝你的指導。 :) – raiph

回答

1

我犯了一個非常愚蠢的錯誤,這就是爲什麼我沒有看到我的預期。您無法約束以@開頭的變量。任何約束都適用於其元素。 Array @array表示我有一個位置排序的東西,其中每個元素是Array。這是the same thing that raiph said。奇怪的是,語法看起來一樣,但它做了不同的事情。這是我以前絆倒過的東西。

,因爲它是在做不同的東西,這不是去上班了,即使數據結構相匹配:

foo([ [1], [2], [3] ]); 
foo([ 1, 2, 3 ]); 

multi foo (Array @array) { put "Called Array @ version" } 
multi foo (Array $array) { put "Called Array \$ version" } 
multi foo (List $list) { put "Called List version" } 
multi foo (Range $range) { put "Called Range version" } 

我仍然得到的版本我不希望基於約束和數據結構:

Called Array $ version 
Called Array $ version 

我認爲這只是普通用戶必須學習的Perl 6的一個瑕疵。

5

爲什麼不調用(Array @array)版本?

您的測試foo調用只有一個陣列([1,2,3])作爲它的參數,而不是一個數組的Array小號(如[[1,2,3],[4,5,6]])。

(在@array@指示值does Positional,例如數組或列表。Array @array表示同樣的事情,但與所述附加約束或陣列,列表的每個元素無論是Array。)

調度員如何做出決定?

簡化,它的採摘最窄的匹配類型:(Diagram of subtype relationships of Array, List and Positional

multi foo (Array  )    {} # Narrowest 
multi foo (List  )    {} # Broader 
multi foo (Positional )    {} # Broader still 
multi foo (@array  )    {} # Same as `Positional` 

對於很多細節見jnthn's authoritative answer to a related SO question

(以及它在哪裏記錄)?

我不確定該文檔。 Multi-dispatch看起來很小。

-1

似乎在設計文檔(更完整但更過時)和文檔(已知不完整,docs.perl6.org承認,但希望更新)之間存在權衡。前者解釋了Synopsis 12中的多分辨率分辨率。摘錄:

當您調用具有特定短名稱的例程時,如果有多個可見的長名稱,則它們都被視爲候選者。根據參數的運行時間類型與每個候選參數的聲明類型的匹配程度,將它們排序爲一個順序。最好的候選人被稱爲,除非有平局,在這種情況下,並列候選人使用任何額外的平局策略(見下文)重新分配。 [...]

有三種打破平局模式,在絕望的順序增加:

A)內或衍生範圍

B)的運行時約束處理

C)使用的候選的標記「是默認的」

Tiebreaker A只是比其他派生範圍內的候選人更偏愛內部派生範圍或更多派生範圍內的候選人。對於同一範圍內的候選人,我們繼續執行決勝局B.

在沒有任何約束的情況下,tiebreaker A中的聯繫人立即故障轉移到tiebreaker C;如果沒有被C解決,他們會在編譯時警告一個模糊的調度。 [...]

我不太瞭解Perl 6來證明它的準確性,但它似乎與raith’s answer一致,並且還涵蓋了其他方面。

+0

這並不能解釋我顯示的行爲。 –

+1

@briandfoy Imo第一部分涵蓋了你所表現出來的行爲:「當你用一個特定的短名稱調用一個例程時,如果有多個可見的長名字,它們都被認爲是候選者,它們按照多近的順序排序參數的運行時類型與每個候選者的參數的聲明類型相匹配,最好的候選者被調用,除非有平局......「沒有平局,所以匹配類型最接近的候選人會贏。 – raiph

2

這是關於「容器」。我不能提出一個完整的規則,但能夠展示一些例子。

有了明確興建貨櫃my @array

my Array @array = [ [1], [2], [3] ]; 

foo(@array); 

multi foo (Array @array) { put "Called Array @ version" } 
multi foo (Array $array) { put "Called Array \$ version" } 

# Ambiguous call to 'foo'; these signatures all match: 
# :(Array @array) 
# :(Array $array) 

如果我們做出一些改變:

my @array = [ 1, 2, 3 ]; 

foo(@array); 

multi foo (@array) { put "Called Array @ version" } 
multi foo (Array $array) { put "Called Array \$ version" } 

# Called Array $ version 

看來Array $array太窄。 my @array = [1, 2, 3]@arrayPositional

foo([ 1, 2, 3 ]); 

multi foo (@array) { put "Called Array @ version" } 
multi foo ($array) { put "Called Array \$ version" } 

# Called Array @ version 

foo([ 1, 2, 3 ]); 

multi foo ($array) { put "Called Array \$ version" } 

# Called Array $ version 

回到第一實例,Array @array意味着該參數是與類型約束陣列的位置的事情,而Array $array意味着它是一個陣列(在某種程度上更「窄」比位置),結果仍然是平局。