'閉包'和'lambda'有什麼區別?

有人能解釋一下嗎 我理解它們背後的基本概念,但我常常看到它們互換使用,我感到困惑。 python

如今咱們在這裏,它們與常規功能有什麼不一樣? 編程


#1樓

並不是全部的閉包都是lambda,並不是全部的lambd都是閉包。 二者都是功能,但不必定是咱們習慣瞭解的方式。 閉包

lambda本質上是一個內聯定義的函數,而不是聲明函數的標準方法。 Lambdas常常能夠做爲對象傳遞。 編程語言

閉包是一種經過引用其主體外部的字段來包圍其周圍狀態的函數。 封閉狀態保持在閉包的調用之間。 ide

在面向對象的語言中,閉包一般經過對象提供。 可是,某些OO語言(例如C#)實現的特殊功能更接近於純函數語言 (如lisp)提供的閉包定義,這些閉包沒有包含狀態的對象。 函數式編程

有趣的是,在C#中引入Lambdas和Closures使函數式編程更接近主流使用。 函數


#2樓

當大多數人想到函數時 ,他們會想到命名函數this

function foo() { return "This string is returned from the 'foo' function"; }

這些是按名稱調用的,固然: spa

foo(); //returns the string above

使用lambda表達式 ,您能夠擁有匿名函數code

@foo = lambda() {return "This is returned from a function without a name";}

經過上面的示例,您能夠經過分配給它的變量調用lambda:

foo();

可是,將匿名函數分配給變量比將它們傳遞給高階函數或從高階函數傳遞更有用,即接受/返回其餘函數的函數。 在不少這些狀況下,命名函數是沒必要要的:

function filter(list, predicate) 
 { @filteredList = [];
   for-each (@x in list) if (predicate(x)) filteredList.add(x);
   return filteredList;
 }

//filter for even numbers
filter([0,1,2,3,4,5,6], lambda(x) {return (x mod 2 == 0)});

閉包能夠是命名函數或匿名函數,可是當它在定義函數的範圍內「關閉」變量時,它就是已知的,即閉包仍將引用具備在其中使用的任何外部變量的環境。封閉自己。 這是一個命名的閉包:

@x = 0;

function incrementX() { x = x + 1;}

incrementX(); // x now equals 1

這彷佛不是不少,但若是這是在另外一個函數中而且你將incrementX傳遞給外部函數怎麼辦?

function foo()
 { @x = 0;

   function incrementX() 
    { x = x + 1;
      return x;
    }

   return incrementX;
 }

@y = foo(); // y = closure of incrementX over foo.x
y(); //returns 1 (y.x == 0 + 1)
y(); //returns 2 (y.x == 1 + 1)

這就是在函數式編程中獲取有狀態對象的方法。 因爲不須要命名「incrementX」,所以在這種狀況下可使用lambda:

function foo()
 { @x = 0;

   return lambda() 
           { x = x + 1;
             return x;
           };
 }

#3樓

lambda只是一個匿名函數 - 一個沒有名稱的函數。 在某些語言中,例如Scheme,它們等同於命名函數。 實際上,函數定義被重寫爲在內部將lambda綁定到變量。 在其餘語言中,如Python,它們之間存在一些(至關沒必要要的)區別,但它們的行爲方式相同。

閉包是關閉定義它的環境的任何函數。 這意味着它能夠訪問不在其參數列表中的變量。 例子:

def func(): return h
def anotherfunc(h):
   return func()

這將致使錯誤,由於func不會關閉 anotherfunc的環境 - h未定義。 func只關閉全局環境。 這將有效:

def anotherfunc(h):
    def func(): return h
    return func()

got closures correct (mutation still doesn't work), this means that it closes over anotherfunc 's environment and can access variables inside of it. 由於在這裏, funcanotherfunc定義,而且在python 2.3及更高版本(或者像這樣的一些數字)中,當它們閉包正確時(變異仍然不起做用),這意味着它關閉了 anotherfunc的環境而且能夠訪問裏面的變量。 在Python 3.1+中,使用nonlocal關鍵字時,變異也起做用。

另外一個重要的一點- func將繼續關閉了anotherfunc ,即便它再也不在評估的環境anotherfunc 。 此代碼也適用:

def anotherfunc(h):
    def func(): return h
    return func

print anotherfunc(10)()

這將打印10。

正如您所注意到的,這與lambda無關 - 它們是兩個不一樣的(雖然相關)概念。


#4樓

從編程語言的角度來看,它們徹底是兩回事。

基本上對於圖靈完整語言咱們只須要很是有限的元素,例如抽象,應用和縮減。 抽象和應用程序提供了構建lamdba表達式的方法,而且減小了lambda表達式的含義。

Lambda提供了一種能夠抽象出計算過程的方法。 例如,爲了計算兩個數的和,能夠抽象出取兩個參數x,y和返回x + y的過程。 在方案中,您能夠將其編寫爲

(lambda (x y) (+ x y))

您能夠重命名參數,但它完成的任務不會更改。 在幾乎全部編程語言中,您均可覺得lambda表達式指定名稱,這些名稱是命名函數。 可是沒有太大的區別,它們在概念上能夠被認爲只是語法糖。

好的,如今想象一下如何實現這一點。 每當咱們將lambda表達式應用於某些表達式時,例如

((lambda (x y) (+ x y)) 2 3)

咱們能夠簡單地用要評估的表達式替換參數。 這個模型已經很是強大了。 可是這個模型不能讓咱們改變符號的值,例如咱們沒法模仿狀態的變化。 所以,咱們須要一個更復雜的模型。 爲了簡化,每當咱們想要計算lambda表達式的含義時,咱們將符號對和相應的值放入環境(或表)中。 而後經過查找表中的相應符號來評估其他(+ xy)。 如今,若是咱們提供一些原語來直接對環境進行操做,咱們能夠對狀態的變化進行建模!

在此背景下,檢查此功能:

(lambda (x y) (+ x y z))

咱們知道,當咱們評估lambda表達式時,xy將被綁定在一個新表中。 可是咱們如何以及在哪裏能夠看到z? 實際上,z被稱爲自由變量。 必須有一個包含z的外部環境。 不然,只能經過綁定x和y來肯定表達式的含義。 爲清楚起見,您能夠在方案中編寫以下內容:

((lambda (z) (lambda (x y) (+ x y z))) 1)

因此z將在外表中綁定爲1。 咱們仍然獲得一個接受兩個參數的函數,但它的真正含義還取決於外部環境。 換句話說,外部環境關閉了自由變量。 在set!的幫助下,咱們可使函數有狀態,即它不是數學意義上的函數。 它返回的不只取決於輸入,還取決於z。

這是你已經很是瞭解的東西,對象的方法幾乎老是依賴於對象的狀態。 這就是爲何有些人說「閉包是窮人的對象。」但咱們也能夠認爲對象是窮人的封閉,由於咱們真的喜歡一流的功能。

我使用方案來講明因爲該方案是最先的具備真正閉包的語言之一的想法。 這裏的全部材料都更好地呈如今SICP第3章中。

總而言之,lambda和閉包是很是不一樣的概念。 lambda是一個函數。 閉包是一對lambda和關閉lambda的相應環境。


#5樓

它就像這樣簡單:lambda是一種語言結構,即簡單函數的語法; 閉包是一種實現它的技術 - 或任何一流的函數,就此而言,命名或匿名。

更準確地說,閉包是在運行時如何表示第一類函數 ,做爲一對「代碼」和一個環境「關閉」該代碼中使用的全部非局部變量。 這樣,即便已經退出它們的外部範圍,這些變量仍然能夠訪問。

不幸的是,有許多語言不支持做爲一等值的函數,或者只支持它們的殘缺形式。 因此人們常用「閉合」這個詞來區分「真實的東西」。

相關文章
相關標籤/搜索