tags:

views:

277

answers:

6

I'm actually reading the book for fun but it might be considered homework. At any event, I don't feel comfortable with local state variables at all with this language... Take for example this code:

(define flip
  (let ((count 0))
    (lambda ()
      (if (= 0 count)
          (begin (set! count 1) count)
          (begin (set! count 0) count)))))

why does this code alternate between 1 and 0? count is given the value of 0 every time this function is called! A python equivalent would be:

class Flip:
    def __init__(self):
        pass
    def __call__(self):
        count = 0
        if count == 0:
            count = 1
            return count
        else:
            count = 0
            return count

This returns the same thing every time. I'm confused...

+2  A: 

Because your flip function actually returns a function (which is defined inside lambda)

Each time you call the returned function it modifies its environment.

If you think about it the let creates the environment (and initializes count to 0) only once - when the lambda function is returned to you.

In a sense lambda creates a function object for you which uses environment, whose last frame was initialized in let with a single variable count. Each time you call your function it modifies its environment. If you call flip a second time it returns another function object with different environment. (count initialized to 0) You can then toggle the two functors independently.

If you want to undestand fully how it works you should read about environmantal model.

EFraim
I think I get it, more or less... The next exercise is to create different instances of flip which can be flipped individually without affecting each other. Is it possible to do that without using the internal mechanism of the original flip procedure?
ooboo
Just call flip twice.
EFraim
Uhm, so how do I create independent fibonacci numbers generators, given a single one? More precisely how can I create different enviornments for different variables?
ooboo
Each time you call lambda, you create a functor, which inherits the environment it was created in. Let is a syntactic sugar for lambda coupled with its application. So let creates a frame for you.
EFraim
I want for example: (define a (make-flip))(define b (make-flip))(b) -> 0(b) -> 1(b) -> 0(a) -> 0(b) -> 1And I tried:(define make-flip (let ((self flip)) (lambda () self)))Why does this not work? This makes flip a global in the enviornment of the lambda, so it's changed when I call it. I want an enviornment where flip is a local but it doesn't work
ooboo
What do you want to do with your last example?
EFraim
I don't know - that's what they ask for in the exercise... I don't understand how you can create objects in this language. Flip is an object which returns 1 or 0 when it is called... how can I create more than one instance of it?
ooboo
+2  A: 

The lambda is a closure. It's a function that references a free variable (count), which, not being locally defined or one of the parameters, is bound to the closest enclosing lexical environment.

The function being called is the lambda, not "flip". Flip is just a name you've given to the lambda that's returned out of the (let ...) expression.

As for the Python, I don't know the language, but it looks like count should be a member of the Flip object, not a variable local to call.

wrang-wrang
A: 

The problem with the original code is that it has a strong influence of the imperative style. A more idiomatic solution will be:

(define (flip)
  (let ((flag #t))
    (lambda ()
      (set! flag (not flag))
      (if flag 1 0))))
Vijay Mathew
I don't see how this is less imperative
Jonas
I said "more idiomatic", not "less imperative". Scheme is not a pure functional language. It is a multi-paradigm language, with support for functional programming.
Vijay Mathew
You should remove the parentheses around 'flip' on the first line, `(define (flip)`.
Pinochle
The parenthesis are required. Note that I used a "convenient" form of define to avoid lambda.
Vijay Mathew
+1  A: 

it's more like

class Flip:
    def __init__(self):
        self.count = 0
    def __call__(self):
        if self.count == 0:
            self.count = 1
            return self.count
        else:
            self.count = 0
            return self.count

Update with more explanation: The function in Scheme is a closure that "closes" around the free variable count, which is defined in the scope outside it. The way that count is defined in a let with just the function as the body, means that the function is the only thing that can access it -- making count effectively a kind of private mutable state that is attached to the function.

This is the way "objects" are traditionally created in Scheme in SICP -- to have a let define a bunch of variables (the instance variables, initialized to their initial values), and in the body define a bunch of functions which are "methods" that have shared access to the instance variables. That is why it is natural here to use a Python class to represent what is going on, with count being an instance variable.

A more literal translation into Python 3.x would be something like this (note that it is only approximate as Python doesn't have a let (limited-scope local variable declaration) syntax, and Python's lambdas can't be used because they don't take statements):

count = 0

def flip():
    nonlocal count
    if count == 0:
        count = 1
        return count
    else:
        count = 0
        return count

# pretend count isn't in scope after this
newacct
You already got my vote, but it would be nice if you would add some explanation like this: The lambda is inside the let, so it captures `count` similar to the way Python references self.count in __call__.
Nathan Sanders
+2  A: 

I have a little experience with writing compilers for functional languages, so perhaps a short description of how that function is stored/represented in memory is in order. Every function can roughly be thought of as a pair (E,F) where E is the set of free variables, and F is the "code" of the function itself. When you call the function, it takes the values in E and substitutes those in for the variables in F, and then executes the code using those values.

So, where your example is concerned, you have defined the variable "flip" to be the function returned by your let expression. That function is the stuff inside your lambda. Because "count" is defined outside the lambda, it's a free variable, so it's stored in the function's environment. Then, every time you call (flip), the interpreter goes to the code in the lambda, sees that it needs to look up the value of "count" in the environment, does that, changes it, and returns. That's why each time you call it, the value stored in "count" persists.

If you want count to be zero every time you call flip, put the let expression inside the lambda, so it's a bound variable instead of a free variable.

maths
This is the explanation I've been looking for. Thank you.However I still can't get the other question - creating multiple instances of flip (i.e, objects).
ooboo
So with this example, to create a function that generates multiple instances of flip, just put the word "flip" in the code you posted in parentheses. That way, instead of associating the lambda function with the identifier "flip," you've created a function that returns those lambdas. Then you can call it and associate the function from above with any identifier you like. This is sort of confusing, so here's an example:(define (flip) (let ... ))(define a (flip))(define b (flip))(a) -> 1 \ (b) -> 1 \ (b) -> 0 \ (a) -> 0. And so on...
maths
A: 

To answer the question in you comment ooboo, you want a function that returns a function

(define make-flipper
  (lambda ()
    (let ((count 0))
      (lambda ()
    (let ((v count))
      (set! count (- 1 count))
      v)))))

;; test it
(let ((flip-1 (make-flipper)))
  (format #t "~s~%" (flip-1))  
  (format #t "~s~%" (flip-1))
  (format #t "~s~%" (flip-1))

  (let ((flip-2 (make-flipper)))
    (format #t "~s~%" (flip-2))
    (format #t "~s~%" (flip-2))
    (format #t "~s~%" (flip-2))))

You can trivially change the set! line so that it becomes a counter, not a flipper (more useful).

Hey david. This is a good way but it does not use encapsulation... the flip function is inside make-flipper. Suppose I do not know the internal mechanism of flip - how can I make a function that returns a function using the original flip ?
ooboo