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

标签 c# f# closures

最近几天,我在努力理解闭包。我非常喜欢 C#,所以我的主要测试平台是这种语言,所以我想了解它的闭包支持。在我研究和实验的过程中,我发现很多人在尝试写关于闭包的博客时,他们是按照完全错误的方向去做的。他们计划使用闭包(例如众所周知的 for 语句)时存在某些错误,并且他们正在尝试对其进行解释。相反,我希望看到一种数学方法(一等公民、自由/绑定(bind)变量、lambda 等)。然而,这让我想到我想知道在不考虑闭包的情况下编码时可能会出现哪些错误。

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

我在大学里没有 FP 类(class),也没有高级编程语言。但我知道副作用在过程代码中的作用,以及它们在纯虚拟语言中不存在的作用。 C# 中的闭包只是一个把戏吗?什么(例如)F# 闭包比 C# 闭包更多?

最佳答案

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

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

Func<int, int> CreateAdder(int num) {
  return arg => arg + num;
}

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

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

闭包 需要捕获lambda 函数 中的所有空闲 变量。这意味着所有在主体内部使用但在其他地方声明的变量都会被捕获。但是,C# 编译器不只是复制当前值。它把它变成一个可变字段,这样它就可以从所有可能访问它的函数中访问(也可以改变)(这也是它变得棘手的地方)。这将是一篇很长的博客文章的主题,但这里有一个简短的示例,您可以用来对此进行试验(使用 .NET 4.0 中的 Tuple,如果您使用的是 VS 2008,则可以获取 C# 实现 here in Chapter03/FunctionalCSharp ):

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

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

有一个proposal by Don Syme from MSR直接向 .NET 添加对闭包的支持。这有点学术性,但可能有助于澄清一些事情。

关于c# - 带闭包的无错误编码(在非纯虚拟环境中),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2064088/

相关文章:

function - 是否可以在 f# 中编写这样的递归分组函数

javascript - 带有对象/原型(prototype)的链式 Promise(Q 延迟)

javascript - 对除 JavaScript 中的一个对象之外的所有对象隐藏对象属性

c# - ASP.NET MVC 路由 : Can I have an action name with a slash in it?

c# - 按钮点击和回发问题

f# - CaSTLe Windsor - DependsOn 在 F# 中不起作用?

f# - 列表 except - 过滤不等于另一个列表的任何 item.A 的字符串序列

swift - swift 3 中的回调语法

c# - 从 Linux 服务器与 C# 桌面应用程序通信的选项?

c# - 如何在C#中使数组值相等?