可能有人解释一下吗? 我理解他们背后的基本概念,但我经常看到他们互换使用,我感到困惑。
而现在,我们在这里,他们是如何从一个普通的功能有什么不同?
可能有人解释一下吗? 我理解他们背后的基本概念,但我经常看到他们互换使用,我感到困惑。
而现在,我们在这里,他们是如何从一个普通的功能有什么不同?
一个lambda只是一个匿名函数-没有名字定义的函数。 在某些语言中,如方案,它们相当于命名功能。 实际上,函数定义重新写为一个lambda内部结合到一个变量。 在其他语言如Python,它们之间存在着一些(而不用)的区别,但它们否则行为相同的方式。
的封闭件是封闭在其中它被定义环境中的任何功能。 这意味着它不能访问它的参数列表中的变量。 例子:
def func(): return h
def anotherfunc(h):
return func()
这将导致一个错误,因为func
不收 , 较环境anotherfunc
- h
是不确定的。 func
只关闭了全球环境。 这将工作:
def anotherfunc(h):
def func(): return h
return func()
因为在这里, func
定义在anotherfunc
,并在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表达式和封锁混乱的,甚至在回答这个在这里StackOverflow的问题。 不要问随机程序员谁了解封从具有特定的编程语言或其他无能的程序员的实践,采取的旅程源 (一切开始的地方)。 而且,由于lambda表达式和封锁来自演算由邱奇早在20世纪30年代第一台电子计算机,甚至出现之前发明的,这是我说的来源 。
演算是世界上最简单的编程语言。 唯一的东西,你可以在里面做:►
fx
。 f
是函数和x
是其唯一的参数) λ
(拉姆达),然后象征性的名称(例如x
),然后一个点.
之前的表达。 这则表达式转换成期待一个参数的函数 。 λx.x+2
获取表达式x+2
,并告诉该符号x
在这个表达式是一个约束变量 -它可以与你提供作为参数的值来取代。 (λx.x+2) 7
。 那么表达式(在这种情况下一个文字值) 7
被取代的如x
在子表达式x+2
所施加的拉姆达,这样就可以获得7+2
,然后降低到9
由共同的算术规则。 因此,我们已经解决了其中的奥秘:
中λ为从上面的例子中的匿名功能 , λx.x+2
。
function(x) { return x+2; }
并可以立即将其应用到一些像这样的参数:
(function(x) { return x+2; })(7)
或者你可以存储这个匿名函数(拉姆达)到一些变量:
var f = function(x) { return x+2; }
这有效地给它一个名字f
,让您稍后查阅它,并把它多次,例如:
alert( f(7) + f(10) ); // should print 21 in the message box
但是你没有给它命名。 你可以立即调用它:
alert( function(x) { return x+2; } (7) ); // should print 9 in the message box
在LISP,lambda表达式是由这样的:
(lambda (x) (+ x 2))
你可以立即将其应用于一个参数,称这样的拉姆达:
( (lambda (x) (+ x 2)) 7 )
正如我所说的,什么拉姆达抽象确实是绑定在其子表达式的象征,使之成为一个substitutible 参数 。 这样的符号被称为绑定 。 但是,如果有在表达其他符号? 例如: λx.x/y+2
。 在这个表达式中,符号x
是由拉姆达抽象结合λx.
它前面。 但是其他的符号, y
,不绑定-它是免费的 。 我们不知道它是什么,它从何而来,所以我们不知道这意味着什么,什么价值它代表,因此直到我们弄清楚什么我们无法评估该表达式y
手段。
事实上,同去与其他两个符号, 2
和+
。 这只是我们非常熟悉这两个符号,我们经常忘记的是,计算机不知道他们,我们需要告诉它什么,他们通过定义它们的地方,例如在图书馆或语言本身的意思。
定义别的地方,表达外,在其“周围语境”,这就是所谓的环境,你能想到的自由符号。 环境可能是一个更大的表达,这种表达的一部分(如奎刚·金说:“总有一个更大的鱼”)),或在一些图书馆,还是在语言本身(作为原语 )。
这让我们划分lambda表达式分为两类:
您可以通过将绑定到某些值通过提供环境 ,它定义了所有这些免费的符号关闭打开的 lambda表达式(可以是数字,字符串,又名lambda表达式匿名函数,无论...)。
这里来密闭部分:
lambda表达式的闭合是这个特定的一组给值到自由符号在该表达式在外部环境(环境)中所定义的符号,使它们非自由了。 原来一个开放的 lambda表达式,其中仍含有一些“不确定的”自由的符号,成为一个封闭的,它没有任何自由的符号了。
例如,如果你有以下lambda表达式: λx.x/y+2
中,符号x
结合,而符号y
是自由的,因此表达是open
和除非你说什么不能评价y
装置(和同样用+
和2
,它们也是免费)。 但是,假设你也有一个这样的环境 :
{ y: 3,
+: [built-in addition],
2: [built-in number],
q: 42,
w: 5 }
这种环境用品全部“未定义”(免费),从我们的lambda表达式符号定义( y
, +
, 2
),和一些额外的符号( q
, w
)。 我们需要定义的符号是环境的这个子集:
{ y: 3,
+: [built-in addition],
2: [built-in number] }
而这恰恰是我们的lambda表达式的封闭 :>
换句话说,它关闭一个打开lambda表达式。 这就是名字关闭在首位来了,这就是为什么这么多的人在这个线程的答案是不太正确的:P
那么,太阳/甲骨文,微软,谷歌等企业marketoids是罪魁祸首,因为这是他们在语言(Java,C#,围棋等),称这些结构。 他们经常打电话都应该做的只是lambda表达式“倒闭潮”。 或者他们所谓的“倒闭潮”,他们用来实现词法范围特定的技术,也就是一个事实,即函数可以访问在其定义的时间在其外部范围中定义的变量。 他们常说的功能“封闭”这些变量,那就是,他们捕捉到一些数据结构从外部函数执行完毕后遭到破坏救他们。 但是这仅仅是编造的呈文后 “民俗词源”和营销,这只是使事情变得更加混乱,因为每个语言供应商使用自己的术语。
而这是因为一个事实,即总有一个有点道理的,他们说什么,这并不让你轻松地将其斥为假更惨:P让我解释一下:
如果要实现使用lambda表达式作为一等公民的语言,则需要允许他们使用在其周围上下文定义的符号(也就是,在你的lambda表达式使用自由变量)。 而这些符号必须在那里,即使周围的函数返回。 问题是,这些符号被绑定到一些本地存储功能(通常是调用堆栈上),这将不会再出现在函数返回时。 因此,为了使拉姆达工作,你所期望的方式,你需要以某种方式从外部语境“捕捉”所有这些自由变量,并保存以供日后,即使在外部情境将会消失。 也就是说,你需要找到自己的拉姆达关闭 (所有这些外部变量,它使用),并将其存储在其他地方(无论是通过复印,或准备为他们的空间前期,别的地方不是堆栈)。 您使用来实现这一目标的方法实际是一个“实现细节”你的语言。 这里的关键是封闭 ,这是一组从拉姆达的环境 ,需要有地方保存自由变量 。
它没有花太长的人开始叫他们用实际的数据结构,在他们的语言的实现,以实现闭合的“闭合”本身。 结构通常看起来是这样的:
Closure {
[pointer to the lambda function's machine code],
[pointer to the lambda function's environment]
}
和这些数据结构被传递围绕作为参数传递给其它功能,从函数返回,并存储在变量,以表示lambda表达式,并允许他们访问其包围的环境以及该机器代码在该上下文中运行。 但它只是一种方式(许多之一) 实施关闭,未关闭本身。
正如我上面所解释的,lambda表达式的闭合是在其环境,为包含在该lambda表达式,有效地关闭的表达(车削一个开放的λ表达式,尚不能评价成游离变量得到的值定义所述子集封闭 lambda表达式,其然后可以被评估,因为包含在其中的所有符号现在定义)。
还有什么是只是一个“货物邪教”和程序员和语言供应商不知道这些概念的真正根源的“VOO斗法宝”。
我希望回答你的问题。 但是,如果你有任何后续问题,随时提出他们的意见,我会尽力解释它更好。
当大多数人认为的功能 ,他们认为的命名函数 :
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";}
与上面的例子中,你可以通过调用它分配给变量的拉姆达:
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;
};
}
并非所有的闭包是lambda表达式,而不是所有的lambda表达式都关闭。 无论是功能,但不一定以这样的方式,我们已经习惯了了解。
一个lambda基本上定义了一个函数为inline而非声明函数的标准方法。 Lambda表达式经常可以绕过为对象。
的封闭是通过参考外部到其主体字段包围其周围的状态的功能。 封闭状态保持整个封闭的调用。
在一种面向对象的语言中,封闭件通常通过对象提供。 然而,一些面向对象语言(如C#)实现特殊的功能更接近于通过纯粹的提供封闭的定义函数式语言没有对象附上状态(如口齿不清)。
有趣的是,引入lambda表达式和闭包在C#中带来了函数式编程更接近主流的应用。
这是像这样简单:拉姆达是一个语言结构,即简单的语法匿名函数; 闭包是实现它的技术 - 或者任何一类函数,对于这个问题,命名或匿名。
更确切地说,一个封闭件是如何头等函数在运行时表示,作为对它的“代码”和一个环境“闭合”过在该代码中使用的所有非局部变量。 这样一来,那些变量,即使它们的来源外范围已经退出仍然可以访问。
不幸的是,很多语言在那里,不支持函数作为第一类值,或仅支持他们残缺的形式。 所以人们常常用“关闭”一词来区分“真实的东西”。
从编程语言的角度看,他们是完全两个不同的东西。
基本上是一个图灵完备的语言,我们只需要非常有限的元素,如抽象,应用程序和还原。 抽象和应用程序提供了可以建立lamdba表达的方式,减少dertermines lambda表达式的含义。
LAMBDA提供了一种方法,你可以抽象的计算过程了。 例如,计算两个数的和,一种方法,其采用两个参数x,y和返回X + Y可以被抽象出来。 在方案中,您可以把它写成
(lambda (x y) (+ x y))
您可以重命名的参数,但它完成任务并没有改变。 在几乎所有的编程语言,你可以给lambda表达式的名称,其命名功能。 但没有太大的区别,它们在概念上可以视为只是语法糖。
OK,现在想像这可以实现。 每当我们运用lambda表达式一些表达式,如
((lambda (x y) (+ x y)) 2 3)
我们可以简单地用表达式替换参数进行评估。 这种模式已经是非常强大的。 但这种模式并没有使我们改变符号的值,例如我们不能模仿的状态的变化。 因此,我们需要一个更复杂的模型。 以使其短,每当我们想要计算拉姆达表达的意思,我们把一对符号和相应的值的到环境中(或表)。 然后其余的(+ X-Y)是通过查找表中的相应的符号进行评价。 现在,如果我们提供了一些原语,对环境的直接操作,我们可以模拟的地位的变化!
在这种背景下,选中此功能:
(lambda (x y) (+ x y z))
我们知道,当我们评估的lambda表达式,XY将在一个新的表约束。 但是如何以及在何处我们可以看看ž吗? 其实z为所谓的自由变量。 必须有一个外包含z中的一个环境。 否则,表达的意义不能仅通过结合X和Y来确定。 为了更清楚些,你可以按照如下方式写的东西:
((lambda (z) (lambda (x y) (+ x y z))) 1)
所以ž将外部表被绑定到1。 我们仍然得到这两个参数,但它的真正含义还取决于外部环境的功能。 换句话说,外部环境对关闭的自由变量。 随着一系列的帮助!我们可以做的功能状态,即,它不是在数学意义上的功能。 它不仅返回取决于输入,但将z作为好。
这是你已经很清楚的东西,对象的方法几乎都依赖于对象的状态。 这就是为什么有些人说“倒闭潮是穷人的对象。”但是,我们也可以,因为我们考虑的对象为穷人的倒闭很喜欢第一类函数。
我使用的方案来说明观点,由于该方案是具有真正的关闭最早的语言之一。 这里所有的材料都好得多在SICP第3章介绍。
综上所述,Lambda和封真的是不同的概念。 一个lambda是一个函数。 的封闭件是一对拉姆达和封闭拉姆达相应的环境。
如上所述的概念是相同的,但如果是从PHP背景,这进一步解释使用PHP代码。
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, function ($v) { return $v > 2; });
函数($ V){$返回V> 2; }是lambda函数定义。 我们甚至可以将其存储在一个变量,因此它可以被重用:
$max = function ($v) { return $v > 2; };
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max);
现在,如果你想改变什么允许过滤数组中的最大值是多少? 你将不得不另写lambda函数或创建一个闭包(PHP 5.3):
$max_comp = function ($max) {
return function ($v) use ($max) { return $v > $max; };
};
$input = array(1, 2, 3, 4, 5);
$output = array_filter($input, $max_comp(2));
闭包是在它自己的环境,它具有可以当函数被调用访问一个或多个绑定变量进行评估的功能。 他们来自函数式编程的世界里,有许多的游戏概念。 闭包是像lambda函数,但他们必须与关闭被定义成外部环境变量交互的能力感更聪明。
这里是PHP封闭的一个简单的例子:
$string = "Hello World!";
$closure = function() use ($string) { echo $string; };
$closure();
在这篇文章中解释很好。
这个问题是老了许多答案。 现在与Java 8和官方LAMBDA是非官方的闭合项目它复兴的问题。
在Java中的上下文答案(通过lambda表达式和封锁-有什么区别? ):
“A闭合是与它的每个自由变量的结合的值的环境配对lambda表达式。在Java中,lambda表达式将被封闭的方式来实现,所以这两个术语都来进行在社区中可互换使用。”
简单地说,关闭是一个关于范围招,拉姆达是一个匿名函数。 我们可以实现关闭与拉姆达更优雅和λ经常被用来作为传递到更高的功能参数
它依赖于功能是否使用外部变量或不执行操作。
外部变量 -变量函数的范围之外定义。
Lambda表达式是无状态的 ,因为它取决于参数,内部变量或常量执行操作。
Function<Integer,Integer> lambda = t -> { int n = 2 return t * n }
封闭件保持状态 ,因为它使用外部变量(函数体的范围之外定义即变量)与参数和常量执行操作沿。
int n = 2 Function<Integer,Integer> closure = t -> { return t * n }
当Java的创建关闭,它使变量n与功能,因此它可以传递给其他功能或任何地方使用时参考。
一个lambda表达式仅仅是一个匿名函数。 在普通的Java,比如,你可以写这样的:
Function<Person, Job> mapPersonToJob = new Function<Person, Job>() {
public Job apply(Person person) {
Job job = new Job(person.getPersonId(), person.getJobDescription());
return job;
}
};
其中功能是内置的Java代码。 现在你可以调用mapPersonToJob.apply(人)的地方使用它。 那只是一个例子。 那是之前有它的语法拉姆达。 lambda表达式此捷径。
关闭:
拉姆达成为当它可以访问此范围之外的变量封闭。 我想你可以说,它的魔力,它奇迹般地能够围住它创造了它的环境和使用的范围(外范围之外的变量。所以要清楚,一个闭合装置的拉姆达可以访问其外部范围。
在科特林,拉姆达总是可以访问它的闭合(即在它的外部范围的变量)