带闭包的无错编码(在非纯虚拟环境中)

Agg*_*dis 2 c# f# closures

最后几天,我正在努力理解闭包.我非常喜欢C#,所以我的主要测试版是这种语言,所以我想了解它的闭包支持.在我研究和实验的过程中,我发现许多人在尝试写关于闭包的博客时,他们是通过遵循完全错误的方向来做到的.他们预计会使用像众所周知的for-statement这样的闭包,他们正试图解释它.相反,我希望看到一种数学方法(一等公民,自由/约束变量,lambdas等).然而,这让我觉得我想知道在没有关闭的情况下进行编码时会出现什么错误.

此外,所有语言对闭包的数学结构都有相同的解释吗?

在uni中我没有FP课程或高级编程语言.但我知道副作用在程序代码中的作用以及它们在纯虚拟语言中不存在的作用.C#中的闭包只是一个技巧吗?什么(例如)F#闭包有多于C#闭包?

Tom*_*cek 5

首先,我认为关于什么应该被称为闭包以及什么应该被称为lambda函数存在一些混淆.我相信正确的方法是在语言中调用语法元素(例如(a, b) => a + b在C#中)lambda函数.创建的值是C#中的函数值委托.

正如在.NET中实现的那样(F#和C#),委托实际上是对某些类中某些方法的引用.原因是使用lambda函数语法构造的委托可能需要保持一些状态:

Func<int, int> CreateAdder(int num) {
  return arg => arg + num;
}
Run Code Online (Sandbox Code Playgroud)

返回的委托引用一些(未命名的)对象,该对象存储num值以及lambda函数的主体.那么,什么是封闭?Closure是对象,它保持运行函数值(或delgate)所需的状态.在这种情况下,它是未命名的对象,从委托引用并保留值num.

您还提到了自由绑定变量.如果你看一下上面例子中的lambda函数,它可以使用两个变量.该变量arg被声明为lambda函数的一部分.这将被称为绑定变量(在lambda函数中),因为它被声明为lambda函数的一部分.该num变量在lambda函数中称为自由变量,因为它仅在lambda函数的范围内使用(但未声明!).它来自外部范围(在本例中为方法声明).

闭合需要捕获所有自由变量的lambda函数.这意味着捕获在体内使用但在其他地方声明的所有变量.但是,C#编译器不只是复制当前值.它将它变成一个可变字段,这样它就可以从可能访问它的所有函数中访问(也可以变异)(这也是它变得棘手的地方).这将是一篇长篇博文的主题,但这里有一个简单的例子,你可以用来试验这个(使用Tuple.NET 4.0,如果你使用VS 2008,你可以在第03章/ FunctionalCSharp中获得C#实现)):

Tuple<Func<int>, Action<int>> CreateReaderAndWriter(int initial) {
   int state = initial;
   return Tuple.Create( (() => state),
                        (newState => { state = newState; }) );
}
Run Code Online (Sandbox Code Playgroud)

当您调用此方法时,您将获得两个函数.第一个允许您读取当前状态,第二个允许您修改它.请注意,状态是共享的(因为它是相同的可变变量)!

来自MSR的Don Syme提出一项直接向.NET添加对闭包的支持的提议.这有点学术性,但它可能有助于澄清一些事情.