2017-08-01 52 views
5

Co to jest Perl 6 sposób odróżnić argument i brak argumentów w bloku bez wyraźnego podpisu? Nie mam na to żadnego praktycznego zastosowania, ale jestem ciekawy.Czy jest to jeden argument, czy nie ma go w przypadku bloku Perl 6?

Blok bez wyraźnego podpisu umieszcza wartość w $_:

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

Podpis jest rzeczywiście ;; $_? is raw. To jeden opcjonalny argument. Zmienna @_ nie jest zdefiniowana w bloku, ponieważ nie ma wyraźnego podpisu.

Tam jest żaden argument, gdzie $_ zostanie zdefiniowana:

&block(); # no argument 

Ale jest również sytuacja, w której jeden argument $_ będą niezdefiniowane. Obiekt typu zawsze jest niezdefiniowany:

&block(Int); 

Ale $_ nic w nim jest faktycznie Any (raczej niż, powiedzmy, Nil). Nie można odróżnić tych dwóch przypadkach:

&block(); 
&block(Any); 

Oto już przykład:

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); 

Zawiadomienie żaden argument i wszelkie formy argumentów pokazują te same rzeczy:

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 

Odpowiedz

1

Oto jak rozwiązać ten. Chciałbym to zrobić w jaśniejszy sposób, ale sprytność języka staje na przeszkodzie i muszę obejść to. Działa to dla parametrów pozycyjnych, ale istnieją głębsze przestrzenie dla nazwanych parametrów i nie będę się nimi zajmować tutaj.

Miałem inne pytanie, Why does constraining a Perl 6 named parameter to a definite value make it a required value?, gdzie odpowiedzi wyjaśniały, że w rzeczywistości nie ma żadnych opcjonalnych parametrów. Istnieją tylko parametry, które mają domyślną wartość i że istnieje domyślna wartość domyślna, jeśli nie przypisuję jawnie jednej.

Sednem mojego problemu jest to, że chcę wiedzieć, kiedy nadałem parametrowi wartość, a kiedy nie. Podaję wartość przez argument lub domyślną wartość domyślną. Domyślną wartością domyślną jest obiekt typu odpowiedniego typu. To jest Any, jeśli nie określiłem typu. Ta domyślna wartość domyślna musi spełniać każde określone przeze mnie ograniczenie.

Pierwszym celem jest ścisłe ograniczenie wartości, które użytkownik może podać po wywołaniu kodu. Jeśli niezdefiniowana wartość jest niepoprawna, nie powinno się zezwalać na jej podanie.

Drugim celem jest łatwe odróżnienie specjalnych przypadków w kodzie. Chcę zmniejszyć ilość specjalnej wiedzy, jakiej potrzebuje część głębszego kodu.

Mogę dostać trzecią sprawę (gdy wiem, że nie było żadnego argumentu lub odpowiedniej wartości domyślnej) przez jawne przypisanie specjalnej wartości, o której wiem, że nie może być nic innego znaczącego. Istnieje wartość, która jest jeszcze bardziej bez znaczenia niż Any. To jest Mu. To najbardziej nieokreślone wartości wszystkich niezdefiniowanych wartości. Numer Any jest jednym z dwóch podtypów: Mu (drugi to Junction), ale prawie nigdy nie powinno się wyświetlać Mu w jednej z wartości w normalnym kodzie. Niezdefiniowane rzeczy w kodzie użytkownika zaczynają się od Any.

Mogę utworzyć wiązanie sprawdzające dla typu, który chcę, lub dla Mu i ustawić wartość domyślną Mu. Jeśli widzę Mu wiem, że nie było żadnych argumentów i że jest to Mu, ponieważ moje ograniczenie to ustawiło.

Ponieważ używam Mu, jest kilka rzeczy, których nie mogę zrobić, np. Użyj operatora ===. Inteligentne dopasowywanie nie zadziała, ponieważ nie chcę testować łańcucha dziedziczenia. Mogę bezpośrednio sprawdzić nazwę obiektu:

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); 

Obecnie większość tych wywołań nie udaje się, ponieważ nie określają właściwych rzeczy.

Jeśli byłyby to rutyny, mogłem zrobić wiele dla niewielkiej liczby przypadków, ale to jeszcze gorsze rozwiązanie. Gdybym miał dwa parametry, potrzebowałbym czterech multis. Przy trzech takich parametrach potrzebowałbym sześciu. To dużo kodu standardowego. Ale bloki nie są rutynami, więc jest to dyskusja tutaj.

2
{ put $_.perl } 

Jest podobny do tego: (co nie działa)

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

Ponieważ domyślnie is default dla $_ zewnątrz bloku jest Any, jeśli nie umieszczać niczego na $_ przed wywołaniem funkcji można dostać Any.


Aby uzyskać coś na wszystkich podobnych, gdzie można odróżnić użyć 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

Wiem o tym wszystkim. Pytam o sprawę, w której umieściłem słowo "Any". –

+0

@briandfoy Jeśli potrzebujesz tych informacji, nie używaj funkcji, która ma na celu sprawienie, by różnica była niewidoczna. –

+1

To nie jest tak, że tego potrzebuję. Patrzę, jak działa język i jego granice, dzięki czemu mogę powiedzieć innym, czego nie będą w stanie zrobić. –

3

O ile mi wiadomo, to jedyny sposób, by poznać numer parametrów przekazywanych bez przeprowadzenia jawny podpis, ma używać @_ wewnątrz ciała, który będzie podpis wygenerować podpis :(*@_).

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

Tak, stary dobry @_ nadal istnieje, jeśli chcesz :-)

+1

Jest to, że nie chcesz wartości w '$ _'. A wartości w @ są niezmienne. –