难以理解 Scheme 中 let 和 lambda 的用法

Difficulty in understanding let and lambda usage in Scheme

我很难理解以下代码的范围:

 (define (create-counter (x 1))
  (let ([count 0])
    (lambda()
      (let ([temp count])
        (set! count (+ x count)) temp))))

如果我使用:

(let ((c (create-counter ))) (+ (c) (c) (c) (c)))

代码工作但是如果我尝试:

(+ (create-counter)(create-counter)(create-counter)(create-counter))

这不起作用,给我一个 0。有人可以帮助我彻底理解这个吗?如果可能的话,请与 C/C++ 等其他语言进行比较,这样我会更容易掌握这一点。谢谢

当您调用 "create-counter" 时,它会创建一个计数器,然后 return 是一个引用该特定计数器的过程。当您调用 "create-counter" 四次时,您将创建四个独立的计数器;每个程序都引用它自己的计数器。当您调用 "create-counter" 一次然后调用结果过程四次时,它只创建一个计数器,并将其递增四次。

很难将它与 C 进行比较,因为 C 和 C++ 在闭包方面非常薄弱; return 在另一个函数内部定义的函数并不容易。

最接近的类比可能是 C++ 中的 "counter" 对象;将 "create-counter" 视为包含单个整数的对象的构造函数,并将生成的过程视为 "increment" 递增该对象中包含的计数器的方法。那么,在您的第二个示例中,您创建了四个不同的对象,而在您的第一个示例中,您创建了一个对象并调用了它的 "increment" 方法四次。

(define (create-counter (x 1))
 (let ([count 0])
  (lambda()
   (let ([temp count])
    (set! count (+ x count)) temp))))

转换为:

auto create_counter(int x=1){
  int count=0;
  return [x,count]()mutable{
    int r=count;
    count+=x;
    return r;
  };
}

返回闭包对象的简单 C++14 函数。

当你这样做时:

(let ((c (create-counter ))) (+ (c) (c) (c) (c)))

是:

auto c = create_counter();
auto r = c()+c()+c()+c();
return r;

它创建一个计数器,然后 运行s 它 4 次,返回 0 1 2 3 并加到 6。

在这种情况下:

(+ ((create-counter))((create-counter))((create-counter))((create-counter)))

是:

auto r = create_counter()()+create_counter()()+create_counter()()+create_counter()();
return r;

它创建了 4 个计数器,并且 运行 每个计数器一次。第一次你 运行 一个计数器你得到 0。所以这加到 0。

闭包对象有状态。每次调用它时 returns 一个更大的数字。

现在你可能对C++11/14 lamnda不熟悉

auto create_counter(int x=1){
  int count=0;
  return [x,count]()mutable{
    int r=count;
    count+=x;
    return r;
  };
}

struct counter {
  int x,count;
  int operator()(){
    int r=count;
    count+=x;
    return r;
  };
};
counter create_counter(int x=1){
  return {x,0};
}

加上一些语法糖。

我修复了您的原始代码中似乎存在语法错误的问题。我不是专家,所以可能我理解错了。

顺便说一句,简要的创建计数器如下所示:

auto create_counter(int x=1){
  return [=,count=0]()mutable{
    int r=count;
    count+=x;
    return r;
  };
}