2017-08-01 49 views
5

什麼是Perl 6的方式來區分沒有明確簽名的塊中的參數和沒有參數?我對此沒有任何實際用途,但我很好奇。這是Perl 6塊的一個參數還是沒有?

沒有明確的簽名塊使價值爲$_

my &block := { put "The argument was $_" }; 

簽名實際上是;; $_? is raw。這是一個可選的論點。因爲沒有明確的簽名,因此塊中未定義變量@_

還有的沒有參數,其中$_將是不確定的:

&block(); # no argument 

但也有地方$_將是不確定的一個參數的情況。 A型對象總是不確定的:

&block(Int); 

但是,什麼也沒有在它的$_實際上是一個Any(而不是說,Nil)。我不能告訴這兩種情況的區別是:

&block(); 
&block(Any); 

這裏有一個較長的例子:

my $block := { 
    say "\t.perl is {$_.perl}"; 

    if $_ ~~ Nil { 
     put "\tArgument is Nil" 
     } 
    elsif ! .defined and $_.^name eq 'Any' { 
     put "\tArgument is an Any type object" 
     } 
    elsif $_ ~~ Any { 
     put "\tArgument is {$_.^name} type object" 
     } 
    else { 
     put "\tArgument is $_"; 
     } 
    }; 

put "No argument: "; $block(); 
put "Empty argument: "; $block(Empty); 
put "Nil argument: "; $block(Nil); 
put "Any argument: "; $block(Any); 
put "Int argument: "; $block(Int); 

通知的任何參數和任何參數的形式表現出同樣的事情:

No argument: 
    .perl is Any 
    Argument is an Any type object 
Empty argument: 
    .perl is Empty 
    Argument is Slip type object 
Nil argument: 
    .perl is Nil 
    Argument is Nil 
Any argument: 
    .perl is Any 
    Argument is an Any type object 
Int argument: 
    .perl is Int 
    Argument is Int type object 

回答

1

以下是我解決了這個。我很樂意以一種更清潔的方式來做到這一點,但語言的聰明卻阻礙了我的工作,我必須解決它。這適用於位置參數,但對於命名參數有更深層次的暗示,我不會在這裏處理這些參數。

我有另一個問題,Why does constraining a Perl 6 named parameter to a definite value make it a required value?,其中的答案澄清說,實際上沒有可選參數。只有參數具有默認值,並且如果我沒有明確指定一個參數,則會有隱式默認值。

我的問題的關鍵是我想知道什麼時候給參數賦值,什麼時候沒有。我通過參數或明確的默認值給它一個值。隱式默認值是正確類型的類型對象。如果我沒有指定類型,那就是Any。該隱式默認值必須滿足我指定的任何約束條件。

第一個目標是嚴格限制用戶在調用代碼時可以提供的值。如果未定義的值無效,則不應允許它們指定一個值。

第二個目標是輕鬆區分代碼中的特殊情況。我想減少深層代碼的某些部分需要知道的特殊知識的數量。

我可以通過顯式指定一個特殊的值來獲得第三種情況(我知道沒有參數或合適的缺省值),我知道它不能是其他有意義的東西。有一個價值比Any更無意義。那是Mu。這是所有未定義值中最未定義的值。 AnyMu(另一個是Junction)的兩個子類型之一,但您幾乎從不會看到Mu以正常代碼中的一個值結尾。用戶代碼中未定義的內容從Any開始。

我可以創建一個約束來檢查我想要的類型或Mu並設置默認值Mu。如果我看到Mu我知道沒有任何參數,並且它是Mu,因爲我的約束設置了該值。

由於我使用的是Mu,有一些我不能做的事情,比如使用===運算符。智能匹配不起作用,因爲我不想測試繼承鏈。我可以直接檢查對象名稱:

my $block := -> 
    $i where { $^a.^name eq 'Mu' or $^a ~~ Int:D } = Mu 
    { 
    say "\t.perl is {$i.perl}"; 

    put do given $i { 
     when .^name eq 'Mu' { "\tThere was no argument" } 
     when Nil    { "\tArgument is Nil"  } 
     when (! .defined and .^name eq 'Any') { 
      "\tArgument is an Any type object" 
      } 
     when .defined { 
      "\tArgument is defined {.^name}" 
      } 
     default { "\tArgument is {.^name}" } 
     } 
    }; 

put "No argument: ";   $block(); 
put "Empty argument: ";  try $block(Empty); # fails 
put "Nil argument: ";  try $block(Nil); # fails 
put "Any type argument: "; try $block(Any); # fails 
put "Int type argument: "; try $block(Int); # fails 
put "Int type argument: "; $block(5); 

現在大多數這些調用失敗,因爲它們沒有指定正確的東西。

如果這些是例行公事,我可以爲少數情況下製作多重播放器,但最終這是一個更糟的解決方案。如果我有兩個參數,我需要四個multis。有三個這樣的參數,我需要六個。這是很多樣板代碼。但是,塊不是例程,所以在這裏沒有意義。

2
{ put $_.perl } 

有點類似於這個:(不起作用)

-> ;; $_? is raw = CALLERS::<$_> { put $_.perl } 

由於默認is default$_外塊是Any,如果你打電話給你弄Any該功能之前,不要將任何東西放入$_


要得到的東西都差不多,你可以看出區別使用Capture

my &foo = -> ;; |C ($_? is raw) { 
    unless C.elems { 
     # pretend it was defined like the first Block above 
     CALLER::<$_> := CALLER::CALLERS::<$_> 
    } 
    my $called-with-arguments := C.elems.Bool; 


    if $called-with-arguments { 
     say 'called with arguments'; 
    } else { 
     say 'not called with arguments'; 
    } 
} 
+0

我知道這一切。我在詢問我把「Any」放進去的情況。 –

+0

@briandfoy如果您需要此信息,請勿使用旨在使差異不可見的功能。 –

+1

這不是我需要它。我正在研究語言是如何工作的,以及它的界限,因此我可以告訴其他人他們無法做到的事情。 –

3

據我所知,只有這樣,才能知道沒有傳遞的參數明確的簽名,就是使用@_內部的正文,其中會生成 a :(*@_)簽名。

my &block := { say "Got @_.elems() parameter(s)" }; 
block;    # Got 0 parameter(s) 
block 42;   # Got 1 parameter(s) 
dd block.signature; # :(*@_) 

呀,好老@_仍然存在,如果你想讓它:-)

+1

這是你不想在'$ _'中進行評估。 @_中的值是不可變的。 –

相關問題