2017-10-05 11 views

Odpowiedz

6

Erlang operator = jest zarówno przyporządkowanie i twierdzenie.

Gdybym to zrobić:

A = 1, 
A = 2, 

mój program padnie. Właśnie powiedziałem, że A = 1, który, gdy A jest niezwiązany (jeszcze nie istnieje jako etykieta), to teraz ma przypisaną wartość 1 na zawsze - do momentu zmiany zakresu wykonywania. Więc kiedy mówię, że A = 2 próbuje twierdzą,, że wartość A jest 2, które nie jest. Więc mamy awarię na złym meczu.

Zakres Erlang jest zdefiniowany przez dwie rzeczy:

  • Definicja bieżącej funkcji. Jest to zakres absolutny na czas trwania definicji funkcji.
  • Definiowanie aktualnej definicji lambda lub listy. Jest to zakres lokalny dla lambda, ale także zamyka się względem wszystkich wartości z zewnętrznego zakresu.

te zakresy są zawsze zastąpiona w momencie ich deklarowanej przez co jest w zakresie zewnętrznej. Tak robimy zamknięcia z anonimowymi funkcjami. Na przykład załóżmy, że mam gniazdo, przez które chcę wysłać listę danych. Gniazdo jest już powiązane z nazwą zmiennej Socket w nagłówku funkcji, a my chcemy użyć operacji listowania do odwzorowania listy wartości do wysłania na efekt uboczny wysłania przez to konkretne gniazdo. Mogę zamknąć ponad wartość gniazda w korpusie lambda, która ma wpływ currying tę wartość z bardziej ogólnym działaniu „wysyłając jakieś dane”:

send_stuff(Socket, ListOfMessages) -> 
    Send = fun(Message) -> ok = gen_tcp:send(Socket, Message) end, 
    lists:foreach(Send, ListOfMessages). 

każdej iteracji operacji listy lists:foreach/2 może przyjąć tylko funkcję arii 1 jako jej pierwszy argument. Stworzyliśmy zamknięcie, które przechwytuje już wewnętrznie wartość Socket (ponieważ była już powiązana w zewnętrznym zakresie) i łączy ją z niezwiązaną, wewnętrzną zmienną Message. Zauważ także, że sprawdzamy, czy gen_tcp:send/2 pracował za każdym razem w lambda, potwierdzając, że wartość zwracana gen_tcp:send/2 była naprawdęok.

To jest bardzo przydatna właściwość .

więc mając to na uwadze, spójrzmy na kod:

1> Total = 15.  
2> Calculate = fun(Number)-> Total = 2 * Number end. 
3> Calculate(6). 

w kodzie powyżej właśnie przypisuje się wartość do Total, utworzono etykietę dla tej wartości (tak jak my co oznacza, przydzielił Socket w powyższym przykładzie). Później jesteś twierdząc że wartość Total jest cokolwiek wynikiem 2 * Number może być - co nigdy nie może być prawdą, ponieważ Total był liczbą całkowitą tak 2 * 7.5 nie będzie go wyciąć albo, ponieważ wynik będzie 15.0 nie 15 .

1> Calculate = fun(Number)-> Total = 2 * Number end. 
2> Total = 15. 
3> Calculate(6). 

W tym przykładzie jednak, że masz się wewnętrzną zmienną nazwie Total który nie zamyka się żadnej wartości zadeklarowanej w zakresie zewnętrznej. Później, użytkownik jest, deklarując etykietę w zewnętrznym zakresie o nazwie Total, ale do tego czasu definicja lambda w pierwszej linii została przekształcona w funkcję abstrakcyjną, a etykieta Total użyta tam została całkowicie podana do niezmiennej przestrzeni nowej definicji funkcji przypisano reprezentację Calculate. Tak więc nie ma konfliktu.

Zastanów się, co się dzieje, na przykład, ze próbuje odwoływać się do wartości wewnętrznej z listy zrozumieniem:

1> A = 2. 
2 
2> [A * B || B <- lists:seq(1,3)]. 
[2,4,6] 
3> A. 
2 
4> B. 
* 1: variable 'B' is unbound 

To nie jest to, czego można oczekiwać od, powiedzmy, Python 2:

>>> a = 2 
>>> a 
2 
>>> [a * b for b in range(1,4)] 
[2, 4, 6] 
>>> b 
3 

Nawiasem mówiąc, ten został naprawiony w Pythonie 3:

>>> a = 2                                                                  
>>> a                                                                   
2                                                                    
>>> [a * b for b in range(1,4)] 
[2, 4, 6]                                                                  
>>> b                                                                   
Traceback (most recent call last):                                                           
    File "<stdin>", line 1, in <module>                                                           
NameError: name 'b' is not defined 

(I chciałbym zapewnić JavaScrip t również dla porównania, ale zasady dotyczące zakresu są tak szalone, że nie ma to znaczenia ...)

5

W pierwszym przypadku masz związany łącznie 15. W Erlang, zmienne są niezmienną, ale w powłoce, gdy piszesz Total = 15., tak naprawdę nie tworzysz zmiennej Total, powłoka robi co może, by naśladować zachowanie, które będziesz miał, jeśli uruchomiłeś aplikację i przechowuje ona w tabeli parę {"Total",15}.

W następnym wierszu definiujesz zabawę Oblicz. Analizator składni znajduje wyrażenie Total=2*Number i przechodzi przez swoją tabelę, aby wykryć, że wcześniej zdefiniowano Total. Ocena zmienia się w coś podobnego do 15 = 2*Number.

Tak więc, w trzeciej linii, gdy pytasz ocenić Calculate(6), to idzie do obliczenia i ocenia 15 = 2*6 i wydaje komunikat o błędzie

exception error: no match of right hand side value 12

W drugim przykładzie, całkowita nie jest jeszcze określona podczas definiowania funkcja. Funkcja jest przechowywana bez przypisania (Total nie jest już używana), przynajmniej nie ma przypisania do zmiennej globalnej. Tak więc nie ma konfliktu, gdy definiujesz Total i nie ma błędu podczas oceny Calculate(6).

Zachowanie będzie dokładnie takie samo w skompilowanym module.

+1

Chyba trzeba dodać trochę informacji o zakresie (kontekście), ponieważ sprawia, że ​​odpowiedź jest bardziej przejrzysta. "Tabela wyszukiwania" nie zawsze jest łatwa do zrozumienia. Niektóre linki: http://learnyousomeerlang.com/higher-order-functions, http://www.erlang.org/course/advanced#scope, http://icai.ektf.hu/pdf/ICAI2007-vol2-pp137 -145.pdf –

+0

@Atomic_alarm: Obawiam się, że masz rację: o) W rzeczywistości wspominam o tej tabeli (słownika procesu, w procesie działającym równolegle do powłoki), ponieważ małe różnice między zachowaniem powłoki i kodu modułu zawsze mnie niepokoiło, szczególnie fakt, że możliwe jest "zapomnienie" zmiennej w powłoce: f (Foo). Ale to prawda, to nie pomaga zrozumieć mojej odpowiedzi, poczułem nawet, że muszę wspomnieć, że działa to samo w module ... – Pascal

1

Zmienna "Total" ma już wartość 15, więc NIE można używać tego samego nazwa zmiennej Razem w drugiej linii. Powinieneś zmienić na inną nazwę Total1 lub Total2 ...

Powiązane problemy