为什么 (c1) return 1、2、3 等等而不是 #<procedure:...make_counter.rkt:8:5>?

Why does (c1) return 1, 2, 3 ect.. and not #<procedure:...make_counter.rkt:8:5>?

这是来自环境模型部分的 SICP 课程:

(define make-counter 
   (lambda (n)    
     (lambda () (set! n (+ n 1))
       n)))    

下面,解释器说(make-counter 0)是一个过程:

> (make-counter 0)
#<procedure:...make_counter.rkt:8:5>

下面,我定义c1(make-counter 0)

(define c1 (make-counter 0)

下面是我对 (c1) return 计数器值而不是 "procedure" 的原因感到困惑的地方。

>(c1)
1
> (c1)
2
> (c1)
3

我的思考过程是,如果(c1)指向一个过程,(make-counter),那么(c1)应该return"procedure:...make_counter.rkt:8:5"

因为程序 -> 程序.

我知道应该发生什么,我只是在概念上对如何以及为什么感到困惑。

你的问题是什么?您是否怀疑它是否像名字所暗示的那样工作,或者您不明白它是如何工作的?

第一个可以在30秒内测试,我来回答第二个:

make-counter 是一个接受一个参数的过程。现在再看一下代码:return 是做什么用的?具有 0 个参数的过程。

因此执行 (c1) 将 return 从 1 开始的数字(如果从 0 开始)。

完整性:

Gambit v4.8.1

> (define make-counter 
   (lambda (n)    
     (lambda () (set! n (+ n 1))
       n)))    
> (define c1 (make-counter 0))
> (c1)
1
> (c1)
2
> (c1)
3
> 

问题编辑后添加:

c1是过程,但(c1)过程应用,在另一个编程世界中你会称之为"calling the procedure"。

> c1
#<procedure #2 c1>
> (c1)
1

顺便说一句,一段不错的函数式代码,如果您理解了这一点,您将以不同的方式看待编程。

更多问题 通过评论:

Now, its (make-counter 0). Working it by hand, I am not understanding why n is not returned.

关于 c1(c1) 的答案是一样的:

make-counter returns lambda (),如果调用 lambda,n 只会被 returned。函数(在方案中:过程、lambda)是可以传递的值,函数式编程原则。你必须打电话给他们(正确的术语:申请)才能得到程序结果。

现在告诉我:在scheme中如何调用过程?

更多编辑

好的,我们通过将它括在括号中来调用方案中的过程。

现在告诉我:(c1) 的替换步骤是什么?

My thinking process is that if (c1) points to a procedure, (make-counter), then (c1) should return "procedure:...make_counter.rkt:8:5".

这是错误的。

这里发生的事情是c1“指向一个过程”,正如你所说,(实际上它是一个绑定到过程的名称)。

你应该记住,在 Scheme 中,形式 (f e1 e2 ... en) 调用 过程 f 的方式,将表达式 f 的值传递给它=13=].

因此,(c1)c1 完全不同:它是一种 调用 过程 c1 的方法(没有参数).每次 interpreter/compiler 计算 (c1) 时,它都会调用增加值的过程 return。

你有

(define make-counter 
   (lambda (n)    
     (lambda () (set! n (+ n 1))
       n)))  

所以评价make-counter

returns

   (lambda (n)    
     (lambda () (set! n (+ n 1))
       n))

和评估 (make-counter 0) 只是用它的值替换该调用中的 make-counter,然后继续作为

( (lambda (n)    
     (lambda () (set! n (+ n 1))
       n))
   0 )
=>
(let ((n 0))    
     (lambda () (set! n (+ n 1)) 
       n))

所以闭包对象被创建并返回,

=>
(closure {environment1: ((n 0))}     ; its own binding for `n`
     (lambda () (set! n (+ n 1)) 
       n))

所以在 (define c1 (make-counter 0)) 这个闭包之后就是 c1 的值。

正在评估c1 returns它的值,上面的过程(闭包)。它的打印表示是依赖于实现的(显示例如 #<procedure> 或类似的东西)。

正在评估 (c1) 调用 这个过程,

(c1)
=>
( (closure {environment1: ((n 0))}     ; its own binding for `n`
     (lambda () (set! n (+ n 1)) 
       n)) )
=>
(under {environment1: ((n 0))}
  (  (lambda () (set! n (+ n 1)) 
       n)) )

不带任何参数调用 ((lambda () ...) ) 只是评估它的主体而不创建任何新环境,因为参数列表是空的并且没有参数:

=>
(under {environment1: ((n 0))}
    (set! n (+ n 1))             ; perform this first
    n )
=>
(under {environment1: ((n 1))}   ; <--- altered binding for `n`!
    n )                          ; now evaluate this and return its value
=>
1

它留下了改变 environment1。当再次调用该过程(闭包)时,(c1),它的环境现在将包含 ((n 1)),因此将更改为 ((n 2)),等等