没有局部变量的状态表示思想的名称
Name of this state representation idea without local variables
我知道这可能是个奇怪的想法,但我想不妨试试在这里问一下。
我在 Racket 中试验没有局部变量的状态表示。
这个想法是定义一个打印它的参数值的函数,如果再次调用它会给我另一个值。由于使用相同参数调用的纯函数总是产生相同的结果,我的变通方法得到了以下结果。
(define (counter n)
(displayln n)
(λ () (counter (add1 n)))) ; unapplied lambda so it doesn't go in a loop
然后我设计了一个函数来调用 counter
及其生成的 lambda 一定次数。
(define (call proc n)
(unless (zero? n)
(let ([x (proc)])
(call x (sub1 n)))))
结果是:
> (call (counter 0) 5)
0
1
2
3
4
5
这里应用的概念叫什么名字?可能它是您在实际应用程序中一直需要的微不足道的东西,但由于我在这方面还没有经验,所以我无法为它确定一个名称。或者也许我只是把一些非常简单的事情复杂化了,但我还是很感激你的回答,这样我就可以进一步研究它了。
抱歉,如果我的问题不够清楚,但英语不是我的母语,问一些我不知道的事情让我感到有点不确定。
您正在使用 closures 来保存状态:lambda
表单存储定义它的环境,并且您不断重新定义过程(在您的代码中称为 x
), 所以每次 "remembers" 都是 n
.
的新值
另一种方法是让过程本身跟踪值 - 换句话说,counter
应该在两次调用之间记住当前的 n
值。这就是我的意思:
(define (counter initial)
(let ((n (sub1 initial)))
(lambda ()
(set! n (add1 n))
n)))
在上面的代码中,counter
的第一次调用 returns 关闭了 n
的新 lambda
,并且每次调用 lambda
修改 n
和 returns 其新值。等价地,我们可以使用 Racket 特定的语法进行柯里化和 begin0
特殊形式来达到相同的效果:
(define ((counter n))
(begin0
n
(set! n (add1 n))))
无论哪种方式,请注意过程如何 "remembers" 它的先前值:
(define proc (counter 0))
(proc)
=> 0
(proc)
=> 1
我们会 call
像这样:
(define (call proc n)
(unless (zero? n)
(displayln (proc))
(call proc (sub1 n))))
(call (counter 0) 5)
=> 0
1
2
3
4
另请注意,上面的代码修复了最初在您的代码中的一个差一错误 - 该过程被调用 六次(从 0
到 5
) 而不是预期的五次,这是因为 call
调用了 counter
五次,但是你在计算 (counter 0)
时又在外面调用了一次 counter
。
我知道这可能是个奇怪的想法,但我想不妨试试在这里问一下。
我在 Racket 中试验没有局部变量的状态表示。 这个想法是定义一个打印它的参数值的函数,如果再次调用它会给我另一个值。由于使用相同参数调用的纯函数总是产生相同的结果,我的变通方法得到了以下结果。
(define (counter n)
(displayln n)
(λ () (counter (add1 n)))) ; unapplied lambda so it doesn't go in a loop
然后我设计了一个函数来调用 counter
及其生成的 lambda 一定次数。
(define (call proc n)
(unless (zero? n)
(let ([x (proc)])
(call x (sub1 n)))))
结果是:
> (call (counter 0) 5)
0
1
2
3
4
5
这里应用的概念叫什么名字?可能它是您在实际应用程序中一直需要的微不足道的东西,但由于我在这方面还没有经验,所以我无法为它确定一个名称。或者也许我只是把一些非常简单的事情复杂化了,但我还是很感激你的回答,这样我就可以进一步研究它了。
抱歉,如果我的问题不够清楚,但英语不是我的母语,问一些我不知道的事情让我感到有点不确定。
您正在使用 closures 来保存状态:lambda
表单存储定义它的环境,并且您不断重新定义过程(在您的代码中称为 x
), 所以每次 "remembers" 都是 n
.
另一种方法是让过程本身跟踪值 - 换句话说,counter
应该在两次调用之间记住当前的 n
值。这就是我的意思:
(define (counter initial)
(let ((n (sub1 initial)))
(lambda ()
(set! n (add1 n))
n)))
在上面的代码中,counter
的第一次调用 returns 关闭了 n
的新 lambda
,并且每次调用 lambda
修改 n
和 returns 其新值。等价地,我们可以使用 Racket 特定的语法进行柯里化和 begin0
特殊形式来达到相同的效果:
(define ((counter n))
(begin0
n
(set! n (add1 n))))
无论哪种方式,请注意过程如何 "remembers" 它的先前值:
(define proc (counter 0))
(proc)
=> 0
(proc)
=> 1
我们会 call
像这样:
(define (call proc n)
(unless (zero? n)
(displayln (proc))
(call proc (sub1 n))))
(call (counter 0) 5)
=> 0
1
2
3
4
另请注意,上面的代码修复了最初在您的代码中的一个差一错误 - 该过程被调用 六次(从 0
到 5
) 而不是预期的五次,这是因为 call
调用了 counter
五次,但是你在计算 (counter 0)
时又在外面调用了一次 counter
。