函数中的变量

2024-04-01

我看到了下面的代码...第一次调用(next-num)回报1,第二个返回2.

(define next-num
  (let ((num 0))
    (lambda () (set! num (+ num 1)) num)))

(next-num)   ; 1
(next-num)   ; 2

我无法理解的是...num是由创建的let inside next-num,它是一种局部变量...scheme 如何知道每次next-num被称为,值num未被擦除let ((num 0));方案如何知道它总是相同的num我们随时修改next-num叫做?

看起来num既是局部变量又是静态变量...我们如何定义局部变量,但不是静态变量?


这是“词汇闭合”,你是对的num,“封闭变量”类似于静态变量,例如在 C 语言中:它仅对 C 语言中的代码可见。let形式(它的“词法范围”),但它在整个程序运行中持续存在,而不是在每次调用函数时重新初始化。

我认为你感到困惑的部分是:“num由let创建next-num,它是一种局部变量”。这是不正确的,因为let块不属于next-num函数:它实际上是一个表达式,它创建并返回函数,然后将其绑定到next-num。 (这与 C 非常不同,例如,C 中的函数只能在编译时创建并通过在顶层定义它们来创建。在Scheme 中,函数是整数或列表之类的值,任何表达式都可以返回它们)。

这是(几乎)相同内容的另一种写法,这使得更清楚的是define只是关联next-num函数返回表达式的值:

(define next-num #f) ; dummy value
(let ((num 0))
  (set! next-num
        (lambda () (set! num (+ num 1)) num)))

重要的是要注意之间的区别

(define (some-var args ...) expression expression ...)

这使得some-var一个执行所有的函数expressions当被呼叫时,并且

(define some-var expression)

这结合了some-var的值expression,当场评估。严格来说,前一个版本是不必要的,因为它相当于

(define some-var
  (lambda (args ...) expression expression ...))

您的代码几乎与此相同,添加了词法作用域变量,num, 周围lambda form.

最后,这是封闭变量和静态变量之间的一个关键区别,这使得闭包更加强大。如果您写的是以下内容:

(define make-next-num
  (lambda (num)
    (lambda () (set! num (+ num 1)) num)))

然后每次调用make-next-num将创建一个带有新的、不同的匿名函数num变量,该函数私有:

(define f (make-next-num 7))
(define g (make-next-num 2))

(f)  ; => 8
(g)  ; => 3
(f)  ; => 9

这是一个非常酷且强大的技巧,它解释了具有词法闭包的语言的许多功能。

编辑添加:你问计划如何“知道”哪个num修改时next-num叫做。总的来说,如果不具体实施的话,这实际上非常简单。 Scheme 中的每个表达式都在变量绑定的环境(查找表)上下文中进行计算,变量绑定是名称与可以保存值的位置的关联。每次评价一个let表单或函数调用通过使用新绑定扩展当前环境来创建新环境。安排有lambda形式表现为闭包,实现将它们表示为由函数本身加上定义它的环境组成的结构。然后通过扩展定义该函数的绑定环境来评估对该函数的调用 -not它被调用的环境。

较旧的 Lisp(包括直到最近的 Emacs Lisp)有lambda,但不是词法范围,因此尽管您可以创建匿名函数,但对它们的调用将在调用环境而不是定义环境中进行评估,因此不存在闭包。我相信Scheme 是第一种做到这一点的语言。萨斯曼和斯蒂尔的原著拉姆达论文 http://library.readscheme.org/page1.html对于任何想要了解范围界定等问题的人来说,关于计划实施的文章都是一本很好的拓展思维的读物。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

函数中的变量 的相关文章

  • C++ 使用对正在定义的变量的引用

    根据标准 不考虑 以下代码是否有效 C bool f T r if r return true return false T x f x x T 众所周知 要在该项目使用的 GCC 版本中进行编译 4 1 2 和 3 2 3 甚至不让我开始
  • 大括号 {} 替换 Racket 中的“开始”

    是否可以有一个宏 使用大括号 来表示一个语句块 从而替换 begin 关键字 因此 代替 if condition begin statement1 statement2 statement3 statement4 else stateme
  • 实际上什么时候创建闭包?

    以下情况是否会创建闭包foo 但不适合bar Case 1 foo是一个带有仅具有全局作用域的作用域链的闭包 Case 2 与案例1相同 Case 3
  • Javascript var 提升问题

    我有一个非常简单的 Javascript 函数 它可以访问 MS SQL 服务器并返回一些记录 有一个单元格 我只想在它唯一时才显示在顶部表格行中 我相信我的问题是 var 提升 因为我在 while 循环中分配的变量不起作用 因为该值不是
  • angularjs foreach循环通过依赖于先前请求的http请求

    我想循环遍历一个数组以角度执行 http jsonp 请求 但是每个请求都会略有不同 具体取决于前一个 http jsonp 请求的时间戳 我试图循环 5 个请求 每个请求都依赖于前一个请求信息 如何执行 foreach 循环来等待每个 h
  • 通过引用调用原型函数时,类失去“this”范围

    谁能向我解释为什么 b 返回未定义以及如何解决这个问题 当我通过引用调用原型函数时 为什么 this 范围会丢失 MyClass function test this test test MyClass prototype myfunc f
  • JavaScript 变量作用域

    我遇到了 JavaScript 全局变量 称为 TimeStamp 未在加载时定义的问题 至少我认为这就是问题所在 我从这里开始 定义时间戳 document ready function AddTest var TimeStamp nul
  • Swift loadItem 关闭未运行

    我正在编写一个共享扩展 但捕获并保存共享附件的闭包未运行 我怎样才能找出原因 switch 分支执行 附件就在那里 没有错误消息 它只是永远不会运行 if let contents content attachments as NSItem
  • 在 python 中检查堆栈中的局部变量

    我编写了一个小函数 它在堆栈中查找一级并查看其中是否有变量 但是我如何将这个函数变成一个可以在堆栈中一直查找直到找到一个局部变量并购买某个特定名称的函数 import inspect def variable lookup variable
  • Angular js中两个$scope数组的区别

    有没有办法返回 angularjs 范围内存在的两个数组之间的差异 例如 scope user1 a b scope user2 a b c d 这两者的区别应该给我另一个 scope user3 c d Underscore js对此有不
  • 将属性类型作为参数传递

    有没有办法将属性作为参数传递给函数 class Car let doors Int 4 let price Int 1000 有没有办法将 Car 属性作为类型传递给函数 我想实现以下目标 func f1 car Car property
  • 强制上下文

    我有一个类 其中有一个私有属性和一个公共访问方法 Person function this Name asd var public new Object public Name function value if value undefin
  • 方案中的尾递归幂函数

    我在方案中编写尾递归幂函数时遇到问题 我想使用辅助函数来编写该函数 我知道我需要一个参数来保存累计值 但在那之后我就陷入了困境 我的代码如下 define pow tr a b define pow tr h result if b 0 r
  • 如何获取调用函数的“this”值?

    如果我有一个这样的函数 function foo this console log this function bar bar prototype func function foo this var test new bar test f
  • 在 Python 2.6 中访问外部作用域

    比如说 我有一些带有变量的作用域 并且在此作用域中调用的函数想要更改一些不可变变量 def outer s qwerty n 123 modify def modify s abcd n 456 是否有可能以某种方式访问 外部范围 就像是n
  • JavaScript:事件处理程序:在哪里声明变量 - 本地变量还是闭包(与开销)?

    我发现自己编写了各种包含事件处理程序的函数 感觉最好在父函数 闭包 的根部声明处理函数所需的变量 特别是如果它们是 jQuery 选择 多个处理程序所需的常量 或者需要一些我不想要的预计算每次触发事件时重复 一个简单的例子 var touc
  • 如何在Spring的applicationContext.xml中指定默认范围来请求范围?

    我想让所有 bean 请求默认作用域 但是 Spring 文档说默认作用域是 Singleton 第 3 4 1 和 3 4 2 节http static springsource org spring docs 2 5 x referen
  • 方案字符串追加?递归复制字符串

    设计一个名为 string dup 的程序 它使用一个字符串 s 和一个数字 n 并返回一个由 s n 次连接而成的字符串 每个 s 实例之间有空格 即 string dup a 3 gt a a a 不使用复制 但我想我们可以使用字符串追
  • 通过 :: 调用包中的函数是一个好习惯吗

    我正在编写一些 R 函数 这些函数在其他包中使用一些有用的函数 例如stringr and base64enc 不打电话好不好library or require 首先加载这些包但要使用 直接引用我需要的功能 比如stringr str m
  • 如何将这段 javascript 代码重写为 C++11?

    这是我在 Javascript Definitive Guide 中看到的 javascript 闭包代码 我想把它写成C 11 var uniqueID1 function var id 0 return function return

随机推荐