简体   繁体   English

了解具有本地状态的对象 - Scheme

[英]Understanding objects with local state — Scheme

i'm studying for my scheme final and objects with local state has always been a tough subject. 我正在为我的计划决赛而学习,与当地国家的对象一直是一个艰难的主题。

Here is a question from my final exam that i need help on. 这是我期末考试中的一个问题,我需要帮助。

(define (make-incrementer n)
  (let ((old 0)
        (new 0))
    (lambda ()
      (cond ((< new n) 
             (set! old new)
             (set! new (+ new 1))
             old)
            (else 
             (set! old 0)
             (set! new 1)
             old)))))

(define a (make-incrementer 3))
(define b (make-incrementer 3))
(define c a)

; 1) (a)
; 2) (a)

why when a is called the second time it returns 1? 为什么当第二次调用a时它返回1? I'm looking at the code and the n we give it is always 3. So wouldn't it always do the else case? 我正在看代码,我们给它的n总是3.所以不会总是做else情况吗?

Welcome to the wonderful world of closures! 欢迎来到精彩的封闭世界! This is a textbook example of how closures in Scheme work. 这是关于Scheme中闭包如何工作的教科书示例。

So make-counter returns a function that has 3 variables that it captures from it's enclosing environment: n , old , new . 因此, make-counter返回一个函数,该函数有3个变量,它从它的封闭环境中捕获: noldnew In this case, the starting environment looks something like 在这种情况下,起始环境看起来像

_name_|_value_
 n    | 3
 old  | 0
 new  | 1

On each invocation, it increments old and new and wraps them around if they're greater than n . 在每次调用时,它会增加oldnew ,如果它们大于n ,则将它们包装起来。 Because it's using set! 因为它正在使用set! , this incrementing is mutating the variables in the lambda's environment, but since these variables are captured from the surrounding environment, they are changed for all future calls as well. ,这种递增是在lambda环境中改变变量,但由于这些变量是从周围环境中捕获的,因此它们也会针对所有未来的调用进行更改。

That's why you get different returns even with the same input. 这就是为什么即使输入相同也能获得不同的回报。

If this seems like witchcraft, you can think of it like objects in more common languages: 如果这看起来像巫术,你可以把它想象成更常见语言的对象:

Eg Python: 例如Python:

class Foo():
    def __init__(self, n, m):
        self.n = n
        self.m = m
    def count(self):
        self.n += 1
        if self.n == self.m:
           self.n = 1
        return self.n-1

f = Foo(0, 2)

f.count() # 1
f.count() # 0

This is the same basic idea except here we're being a bit more explicit about where the environment is coming from, self . 这是一个基本的想法,除了这里我们对环境的来源, self更加明确。 In Scheme, we mimic this with the lambda capturing the surrounding variables. 在Scheme中,我们用lambda捕获周围的变量来模仿它。

For more, check out SICP 有关更多信息,请查看SICP

Here are some examples, that might help with the concept of capturing state: 以下是一些示例,可能有助于捕获状态的概念:

(define (always x) 
  (lambda rest x))
(define always-true (always #t))
(always-true #f)
-> #t

(define (add-n n) 
  (lambda (m)
    (+ n m)))
(define add-1 (add-n 1))
(add-1 10)
-> 11

(define (complement predicate)
  (lambda (x)
    (not (predicate x)))
(define not-positive? (complement positive?))
(not-positive? -1)
-> #t

Next is an example where the captured state, in this case l , is mutated. 接下来是捕获状态(在这种情况下为l )被突变的示例。 This is similar to your case where new and old are captures and modified. 这类似于你的情况下newold的捕获和修改。

(define (nexting l)
  (lambda ()
    (if (null? l)
        '()
        (let ((answer (car l)))
          (set! l (cdr l))
          answer))))
(define next-user (nexting '(Alice Bob David)))
(next-user)
-> Alice
(next-user)
-> Bob
(next-user)
-> David
(next-user)
'()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM