原文在此Apropos proto: Perl6.c multi thoughts
Multi 程序相當(dāng)整潔, 但對于我來說是不徹底的。一些背景 — 有人可能這樣計(jì)算階乘:
multi fac(0) { 1 }
multi fac(Int $n where 1..Inf) { $n * fac( $n-1 ) }
say fac(4); # 24
現(xiàn)在假設(shè)我們要把我們的遞歸 multi-sub 作為一個回調(diào)傳遞會怎樣呢?
given &fac -> $some_fun { say "some_fun(4)=", $some_fun(4) }
現(xiàn)在... 定義一個匿名的 multi-sub 怎么樣?
my $anon_fac = do {
multi hidden_fac(0) { 1 }
multi hidden_fac(Int $n where 1..Inf) { $n * fac( $n - 1 ) }
&hidden_fac };
say $anon_fac(4); # 24
這也會有作用, 但是有點(diǎn) hack 的味道, 并且我們的 multi-sub 并不是真正的匿名。它僅僅是被隱藏了。真正匿名的對象不會在任何作用域中安裝, 而在這個例子中, "hidden_fac" 被安裝在 "do" block 中的本地作用域中。
Perl 6說明書沒有排除匿名的 multi 程序, 而且事實(shí)上
my $anon_fac = anon multi sub(0) { 1 }
會報(bào)一個錯誤:
Cannot use 'anon' with individual multi candidates. Please declare an anon-scoped proto instead
不能對單獨(dú)的 multi 候選者使用 anon
。請聲明一個 anon-scoped 的 proto 代替。
讓我們回到原先那個以 "multi fac(0) { 1 }" 開始的例子。當(dāng)編譯器看到它, 就會在同一個作用域中為我們創(chuàng)建一個"proto fac" 作為 multi 定義。proto 的作用就像一個分發(fā)器(dispatcher) — 從概念上講, 當(dāng)我們調(diào)用 fac(4) 的時候, 我們讓 proto fac 為我們從 multi facs 中挑選一個出來以調(diào)用。
我們可以提前顯式地定義一個 proto, 而且我們甚至能通過指定它的所有程序都需要 Int 類型的參數(shù)來對默認(rèn)的 "proto" 加以改良。
proto fac_with_proto(Int) { * }
multi fac_with_proto(0) { 1 }
multi fac_with_proto(Int $n where 1..Inf) { $n * fac( $n - 1 ) }
say fac_with_proto(4); # 24
因此, anon muiti sub 拋出的錯誤 — Please declare an anon-scoped proto instead — 正是告訴我們 "沒有要安裝到的作用域, 我不能為你獲取一個 proto。 使用你自己的 anon proto, 并把這個程序附加給它"。
好的, 花蝴蝶, 感謝你的提醒! 我試試...
my $fac_proto = anon proto uninstalled-fac(Int) { * };
say $fac_proto.name; # uninstalled-fac
好極了! 現(xiàn)在所有我們要做的就是給那個 proto 添加 multis。
$fac_proto 是一個 Sub 對象, 它有方法來告訴你候選者, 但是沒有辦法設(shè)置(set) 候選者。并且我找不到任何方式在創(chuàng)建時傳遞一個候選者列表。
適當(dāng)?shù)男扪a(bǔ)
什么會讓 proto/multi 干凈并且正交是一種方式去
- 在編譯時指定候選者
- 在運(yùn)行時添加候選者
這有點(diǎn)像
my $future_fac = Proto( :dispatch( sub (Int) {*} ),
:candidates( [sub (0) {1}] ),
:mutable );
$future_fac.candidates.push(
sub (Int $n where 1..Inf) { $n * fac( $n-1 ) }
);
$future_fac(4); # 24
我假定了一個 Sub 的子類 Proto 以揭露 multi 程序的內(nèi)部工作原理。這個構(gòu)造函數(shù)會允許定義任何 proto 聲明符所做的: 簽名 & 默認(rèn)程序和名字。 還有, 它會允許在初始的候選者列表中傳遞一個屬性。
最后, 那個對象自身會讓候選者方法返回一個數(shù)組, 而不是一個不可變列表, 如果 Proto 是使用 mutable 屬性創(chuàng)建的話。不指定 mutable 將意味著所有的 multis 需要在編譯時添加, 而不允許在運(yùn)行時添加。