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 ...)
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 –
@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