有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
有人能解释一下吗?我理解它们背后的基本概念,但我经常看到它们互换使用,我感到困惑。
现在我们到了这里,它们和普通函数有什么不同?
当前回答
并不是所有的闭包都是lambdas,也不是所有的lambdas都是闭包。两者都是函数,但不一定是以我们习惯的方式。
lambda本质上是一个内联定义的函数,而不是声明函数的标准方法。lambda可以经常作为对象传递。
闭包是一种函数,它通过引用其主体外部的字段来封闭其周围的状态。封闭状态在闭包调用之间保持不变。
在面向对象语言中,闭包通常是通过对象提供的。然而,一些面向对象语言(如c#)实现的特殊功能更接近于纯函数式语言(如lisp)所提供的闭包的定义,后者没有对象来封装状态。
有趣的是,在c#中引入lambda和闭包使函数式编程更接近主流用法。
其他回答
闭包意味着一个函数返回另一个函数。不是结果,而是像委托一样的可调用函数。 Lambda是一个匿名函数描述。如果lambda返回一个函数,它也可以是一个闭包。
从编程语言的角度来看,它们完全是两种不同的东西。
基本上,对于图灵完备语言,我们只需要非常有限的元素,例如抽象、应用和还原。抽象和应用提供了构建lambda表达式的方法,而约简决定了lambda表达式的含义。
Lambda提供了一种将计算过程抽象出来的方法。 例如,要计算两个数字的和,可以抽象出一个接受两个参数x、y并返回x+y的过程。在scheme中,可以写成
(lambda (x y) (+ x y))
您可以重命名参数,但它完成的任务不会改变。 在几乎所有的编程语言中,您都可以为lambda表达式指定一个名称,即命名函数。但是没有太大的区别,它们在概念上可以被认为只是语法糖。
好,现在想象一下这是如何实现的。当我们将lambda表达式应用于某些表达式时,例如。
((lambda (x y) (+ x y)) 2 3)
We can simply substitute the parameters with the expression to be evaluated. This model is already very powerful. But this model doesn't enable us to change the values of symbols, e.g. We can't mimic the change of status. Thus we need a more complex model. To make it short, whenever we want to calculate the meaning of the lambda expression, we put the pair of symbol and the corresponding value into an environment(or table). Then the rest (+ x y) is evaluated by looking up the corresponding symbols in the table. Now if we provide some primitives to operate on the environment directly, we can model the changes of status!
有了这个背景,检查这个函数:
(lambda (x y) (+ x y z))
我们知道,当我们求lambda表达式的值时,x y将被绑定到一个新的表中。但是我们怎样才能查到z呢?实际上z是一个自由变量。一定有一个外在的 否则,表达式的含义不能仅通过绑定x和y来确定。为了清楚地说明这一点,可以在scheme中这样写:
((lambda (z) (lambda (x y) (+ x y z))) 1)
所以z在外层表中被绑定为1。我们仍然得到一个接受两个参数的函数,但它的真正含义也取决于外部环境。 换句话说,外部环境对自由变量关闭。在set的帮助下!,我们可以使函数有状态,也就是说,它不是数学意义上的函数。它的返回值不仅取决于输入,还取决于z。
这是你们已经非常了解的东西,对象的方法几乎总是依赖于对象的状态。这就是为什么有人说“闭包是穷人的东西”。但我们也可以把对象看作穷人的闭包,因为我们真的喜欢第一类函数。
我用scheme来说明这个想法,因为scheme是最早的有真正闭包的语言之一。这里的所有材料在SICP第3章中都有更好的呈现。
总之,lambda和闭包是完全不同的概念。A是一个函数。闭包是一对lambda和对应的闭包环境。
并不是所有的闭包都是lambdas,也不是所有的lambdas都是闭包。两者都是函数,但不一定是以我们习惯的方式。
lambda本质上是一个内联定义的函数,而不是声明函数的标准方法。lambda可以经常作为对象传递。
闭包是一种函数,它通过引用其主体外部的字段来封闭其周围的状态。封闭状态在闭包调用之间保持不变。
在面向对象语言中,闭包通常是通过对象提供的。然而,一些面向对象语言(如c#)实现的特殊功能更接近于纯函数式语言(如lisp)所提供的闭包的定义,后者没有对象来封装状态。
有趣的是,在c#中引入lambda和闭包使函数式编程更接近主流用法。
这个问题已经12年了,我们仍然把它作为谷歌中“闭包vs lambda”的第一个链接。 所以我不得不说,因为没有人明确地说过。
Lambda表达式是一个匿名函数(声明)。
一个闭包,引用Scott的《编程语言语用学》解释为:
创建引用环境的显式表示(通常是当前调用子例程时执行的环境),并将其与子例程的引用捆绑在一起,称为闭包。
也就是说,它就像我们所说的“函数+投降上下文”的捆绑。
当大多数人想到函数时,他们想到的是命名函数:
function foo() { return "This string is returned from the 'foo' function"; }
当然,这些都是按名字命名的:
foo(); //returns the string above
使用lambda表达式,你可以有匿名函数:
@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;
};
}