2013-06-20 18 views
7

Zastanawiam się, jak mogę to zrobić w Perlu co ja zwykle zrobić w Lisp:zmienne dynamiczne w Perl

(defvar *verbose-level* 0) 
(defun my-function (... &key ((:verbose-level *verbose-level*) *verbose-level*) ...) ...) 

oznacza to, że my-function prowadzony jest na obecnym poziomie gadatliwości, ale może on przechodzić inny poziom, który wpłynie na wszystkie swoje połączenia za:

(defun f1 (&key ((:verbose-level *verbose-level*) *verbose-level*)) 
    (format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*) 
    (f2 :verbose-level 1) 
    (format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*) 
    (f2 :verbose-level (1+ *verbose-level*)) 
    (format t "~S: ~S=~S~%" 'f1 '*verbose-level* *verbose-level*)) 
(defun f2 (&key ((:verbose-level *verbose-level*) *verbose-level*)) 
    (format t "~S: ~S=~S~%" 'f2 '*verbose-level* *verbose-level*)) 
[17]> (f1) 
F1: *VERBOSE-LEVEL*=0 
F2: *VERBOSE-LEVEL*=1 
F1: *VERBOSE-LEVEL*=0 
F2: *VERBOSE-LEVEL*=1 
F1: *VERBOSE-LEVEL*=0 
NIL 
[18]> (f1 :verbose-level 4) 
F1: *VERBOSE-LEVEL*=4 
F2: *VERBOSE-LEVEL*=1 
F1: *VERBOSE-LEVEL*=4 
F2: *VERBOSE-LEVEL*=5 
F1: *VERBOSE-LEVEL*=4 

(pamiętać, że zmienne są przywracane wiązania na wyjściu - nawet nienormalny - od funkcji).

Jak mogę zrobić coś takiego w Perlu?

Np. W misc.pm, mam our $verbose=0;. Jak napisać funkcję, która zwiąże $verbose z wartością jego argumentu i przywróci jej wartość po powrocie?

Odpowiedz

10

Koncepcja zmiennych globalnych Perla jest bardzo podobna do zmiennych specjalnych w CL.

Można „cień” wartość zmiennej globalnej z local:

our $var = 1; 

func("before"); 

{ 
    # a block creates a new scope 
    local $var = 2; 
    func("inside"); 
} 

func("after"); 

sub func { say "@_: $var" } 

wyjściowa:

before: 1 
inside: 2 
after: 1 

jeśli local jakąś wartość, nowa wartość jest widoczna w całym zakresie dynamicznym , tzn. we wszystkich funkcjach, które są wywoływane. Stara wartość zostaje przywrócona, gdy zakres leksykalny zostanie pominięty w dowolny sposób (błędy, zwroty itp.). Ogonowe połączenia nie rozszerzają zakresu dynamicznego, ale są liczone jako zakończenie zasięgu.

Należy pamiętać, że zmienne globalne mają pełną nazwę. Z innego pakietu, byś zrobił coś podobnego

local $Other::Package::var = 3; 
Other::Package::func("from a package far, far away"); 

ten jest powszechnie stosowany w celu zapewnienia konfiguracji dla pakietów z funkcjonalnego interfejsu (non-OO). Ważne przykłady to: Carp i Data::Dumper.

+1

Zabawne jest widzieć podobieństwa między Perl i CL. Zaczynając od modelu kompilacji (dlaczego * nie powinno się * kodu wykonywać podczas parsowania?) Przez znaki specjalne vs. leksykalne do oddzielnych przestrzeni nazw (CL: zmienne, funkcje, etykiety, strumienie, ...; Perl: skalary, tablice, skróty, subs, IO, ...).Aha, i CLOS/Moose są oczywiście spokrewnieni – amon

3

Jeśli rozumiem cię poprawnie, musisz lokalnie zastąpić zmienną globalną wewnątrz funkcji.

package my_package; 
our $verbose = 0; 

sub function { 
    my ($arg1, $arg2) = @_; # getting function arguments. 
    local $verbose = $arg1; 
} 

Przywróci stary stan $verbose po powrocie.

+0

Dzięki. Co jeśli funkcja 'function' zostanie wywołana bez argumentów? Oznacza to, że '$ arg1' jest niezwiązane. Czy muszę odwołać się do 'local $ verbose = defined $ arg1? $ arg1: $ verbose' lub czy istnieje ładniejsze podejście? – sds

+0

Możesz napisać 'local $ verbose = $ arg1 jeśli zdefiniowano $ arg1;'. –

+0

To nie ma sensu. Jeśli '$ arg1' nie jest zdefiniowany, to' $ verbose' będzie niezdefiniowany. Co możesz zrobić, to 'local $ verbose = shift; $ verbose = "default" jeśli nie jest zdefiniowany $ verbose; '(Lub użyj operatora defined lub assign:' $ verbose // = "default" '). – TLP