机器|设计闭包(Closure)的初衷是为了解决什么问题?

机器|设计闭包(Closure)的初衷是为了解决什么问题?

文章图片

机器|设计闭包(Closure)的初衷是为了解决什么问题?

文章图片


闭包是函数式编程及其核心思想“Lambda 计算法”(Lambda Calculus)的必备基本设定 , 我们都知道:
函数式编程有一个特点 , 就是所有操作都用可计算的函数(computable function , 下简称“函数”)来体现 。 函数的两个特点 , 就是每个函数都有一个输入值 , 一个输出值 。
函数还有一个定律 , 就是给定一个确定的输入值 , 总能得到一个确定的输出值 , 即输入与输出有严格的一一对应关系 。 (当然还有副作用之类的 , 此处不论 。 )

第一是抽象 。 既然所有“多参数函数”都可以抽象成一个高级的“单参数函数”(用上面的方法) , 那么意味着“多参数函数”本身是有信息冗余的 。 这个抽象的过程就像是拆掉分子分母的公约数一样 , 去掉了这个冗余 。
第二是计算 。 我们想象一下任何一种“计算机器” , 它要做一个最简单的加法 , 那么它需要:

  1. 读取 a , 保存
  2. 读取 b , 计算 a + b
  3. 返回结果 。
那么可以看出 , 在第 1 步时如果这个机器暂停 , 那么实际上它保存了一个“状态”(state) , 而没有进行任何“计算” 。

如果把这个保存了某个状态的机器视作是一个新的机器(在内存里写死了 a 值 , 等待 b 值做加法) , 那么新的机器才是真正在做“计算” 。 原来什么值都没有保存的机器有没有在做计算呢?我们不妨认为它也在做“计算” , 这个计算的参数则是 a 值 , 计算结果就是前面说的新机器 。
在解决异步编程的内存管理问题上十分有意义 。 只要我们目前使用的计算机硬件架构没有翻天覆地的改变 , 那么内存管理方案始终是绕不开围绕着作用域的 , 比如C++的RAII以及其延伸出的引用计数 , 所有权等 。
因为作用域非常适合强调上下文关联的逻辑 。 但异步编程的问题就在于 , 它不按套路出牌 , 不是按照指令式编程的上下文关系来执行 , 而是东一榔头西一棒槌 , 这就导致内存管理的难度大幅度上升 。

那解决方案基本分两类 , 要么干脆放弃内存管理 , 高高的举起自己的小白旗并把生杀大权交给GC , 这种自然不在讨论范围内 , 另一种方案就是让异步事件保留自己需要用到的资源的生命周期所有权或知情权 。
大多数语法糖的设计目的都是为了代码复用 。
假设连续的代码块{A{B{C , 代码块B多次出现在不同函数中 , 为了不想重复的敲打代码块B , 聪明的小伙伴们会把代码块B包装成一个函数吧 。

这时候出现了另一种情况 , 有一个函数代码块ABC一个函数ADC 。 这TM就中间不一样 , 上下文都一样 , 想轻松解决复用问题咋整?闭包 装饰器等可以轻而易举地解决这个问题 。
【机器|设计闭包(Closure)的初衷是为了解决什么问题?】最典型的例子就是Python里文件读写 。 正常语言流程都是createfile->openfile->writefile->flushfile->closefile 。 而Python直接使用with语句进行上下文管理 , 你只需要写文件数据 而不需要创建和关闭文件 。 这是contextlib装饰器完成的