Alex Goft
Alex Goft

Reputation: 1124

defined variable in let changed when function called twice

Consider the following code:

(define f2!
  (let([n 0])
    (lambda()
      (set! n (add1 n))
      n)))
(f2!)
(f2!)

I would expect the output to be 1 1, since every time we call f2!, n will be redefined to 0.

But the output is: 1 2. Why is that?

Upvotes: 1

Views: 88

Answers (2)

Neowizard
Neowizard

Reputation: 3017

let is a syntactic sugar for an applied lambda, so it might be easier for you to see the reason for this using the expended form for let:
(define f2! ((lambda (n) (lambda () (set! n (add1 n)) n)) 0)) So when you define f2!, you apply a lambda (2nd line) while binding its parameter, n, to the scheme object 0 (4th line). The definition of f2! is the result of that application, another lambda object. That internal lambda has an environment which contains the parameters of the first lambda (namely n). Not a copy of those parameters, but and actual reference to them, so when you apply that internal lambda and set! the value of n, you're setting the value of the referenced n as was bound when you first defined f2!.

TL;DR, you defined f2! once, at which point you bound n, and from that point on you're getting and setting that same n.

Upvotes: 1

Sylwester
Sylwester

Reputation: 48745

You have made a function that is closed over a variable. In short this is a poor mans OO.

When you call f1! the same free binding n (instance variable) will be mutated and returned. You have created a counter.

You can do the same in many languages since most of them are lexical. eg. JS:

const fBang = (() => {
  let n = 0;
  return () => ++n;
})();

console.log(fBang()); // prints 1
console.log(fBang()); // prints 2

Upvotes: 2

Related Questions