2017-10-05 42 views

回答

6

在二郎山=運營商既分配斷言

如果我這樣做:

A = 1, 
A = 2, 

我的程序會崩潰。我剛剛告訴它,A = 1哪個,當A未被綁定(尚未作爲標籤存在)時,它現在被永久賦值1,直到執行範圍發生變化。那麼當我告訴它A = 2它試圖斷言A的值是2,事實並非如此。所以我們遇到了一場糟糕的比賽。

  • 當前函數的定義:在二郎山

    範圍由兩件事情定義。在函數定義期間,該範圍爲絕對值

  • 當前lambda或列表理解的定義。這個範圍是本地到lambda,但也關閉來自外部作用域的任何值被引用。

這些示波器是總是在它們被無論是在外部聲明時間所取代。這就是我們如何使用匿名函數進行閉包。例如,假設我有一個套接字,我想發送一個數據列表。套接字已經綁定到函數頭部的變量名稱Socket,並且我們希望使用列表操作來映射要發送的值列表,以便通過特定套接字發送的副作用。

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

列表操作的每次迭代:我可以一個lambda的身體,有譁衆取寵該值超出「發送一些數據」更普遍的操作效果內關閉在插座的價值lists:foreach/2只能接受arity 1的函數作爲其第一個參數。我們已經創建了一個閉包,它已經在內部捕獲Socket的值(因爲它已經在外部範圍內綁定),並將其與未綁定的內部變量Message結合。還要注意的是,我們正在檢查gen_tcp:send/2是否每次都在拉姆達內工作,因爲聲稱gen_tcp:send/2的返回值爲確實是ok

這是一個超級有用的財產

所以考慮到這一點,讓我們看看你的代碼:

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

在上面的代碼中你只是分配一個值Total,你已經創建了一個標籤,該值(就像我們的意思在上例中已經分配了Socket)。再後來你斷言說的Total值是什麼的2 * Number結果可能是 - 這絕不是真實的,因爲Total是一個整數,所以2 * 7.5不會削減它要麼,因爲結果將是15.0,不15

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

在這個例子中,雖然你有叫Total內部變量不封蓋外範圍內聲明的任何值。後來,在外部範圍中聲明瞭一個名爲Total的標籤,但此時第一行上的lambda定義已被轉換爲抽象函數,並且標籤Total已被完全賦予不可變的空間新功能定義的分配以Calculate爲代表。因此,沒有衝突。

考慮發生了什麼,例如,與試圖從列表理解引用的內在價值:

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 

這不是你們想的,說會發生什麼,巨蟒2:

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

順便說一句,這已經在Python 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 

(我會提供一個JavaScrip T的範例也是如此,但是那裏的範圍規則只是如此絕對瘋狂,它甚至不重要......)

5

的在第一種情況下,你已綁定到總15.二郎,變量被不變,但在shell中寫入時Total = 15.您並不真正創建變量Total,shell會盡其所能模仿您將擁有的行爲你正在運行一個應用程序,它將一對{"Total",15}存儲在一個表中。

在下一行中,您定義了有趣的計算。解析器找到表達式Total=2*Number,並通過它的表檢測Total是否被定義。評估變成了相當於15 = 2*Number的東西。

因此,在第三行,當你問到評估Calculate(6),它關係到計算和評估15 = 2*6,併發出錯誤信息

exception error: no match of right hand side value 12

在第二個例子中,總還沒有定義,當你定義功能。該函數沒有賦值而被存儲(總計不再使用),至少沒有賦值給全局變量。所以當你定義Total時沒有衝突,當你評估時沒有錯誤Calculate(6).

這個行爲在編譯模塊中是完全一樣的。

+1

我想需要添加一些有關範圍(上下文)的信息,因爲它的答案更清晰。 「搜索表」並不總是容易理解。一些鏈接: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:恐怕你是對的:o)事實上,我提到這個表(一個進程字典,在一個與shell並行工作的進程中),因爲shell行爲和模塊代碼一直困擾着我,特別是可以「忘記」shell中的一個變量的事實:f(Foo)。但它是正確的,它無助於理解我的答案,我甚至覺得有必要提到它在模塊中的作用是一樣的...... – Pascal

1

變量'Total'已經被賦值15,所以你不能使用相同的第二行中的變量名稱總數。你應該更改爲其他名稱Total1或Total2 ...

相關問題