Search code examples
schemelazy-evaluationthunk

Please explain coding for "thunks."


I have the following code I've tried from the book.

;pg 51 "The Scheme Programming Language" by R. Kent Dybvig"
(define lazy
    (lambda (t)
     ;so lazy accepts argument t
        (let ([val #f] [flag #f])
           ;isn't val <- #f (& flag <- #f) ea. time, 
           ;and if so, how is other val returned?
            (lambda () ;operates on no arguments
                (if (not flag)
                    (begin (set! val (t)) 
                     ; if flag == #f (as it initially is) 
                     ; then val <- t, the argument to lazy
                        (set! flag #t)))
                val)))) ; returns val regardless,
                        ; and executes it?

(define p
    (lazy (lambda () 
      ;so this lambda w/o arguments gets 
      ; passed to t above
            (display "sig1 ") 
            ;these 2 lines are printed only
            ; first time, but why?
            (display "sig2 ")
            "sig 3" ))) 
      ;this seems to get printed every time 
      ;as if it were the only argument in p 
      ;to pass to t

; invoke with (p)

; "When passed a thunk t (a zero-argument procedure), 
; lazy returns a new thunk that, when invoked, 
; returns the value of invoking t."

; That is way too convoluted to easily understand!

; What is the new thunk - a copy of the one 
; sent to it, in this case (p)?

; Is this sort of a call-back function?

It works per the book, but I can't understand it. Please see the comments above and questions. I may have assumed incorrect things in my comments. Also, I'm coming from a C background and trying to get my head around this new scheme way of programming. I'm very much a beginner here. Thank you!


Solution

  • The idea behind this thunk is that the lambda it wraps doesn't get called unless you need it, and it stores the value from calling the wrapped lambda so that the lambda is called only once. You can pass a thunk into a function and not have to worry about wasting resources if that function calls it too much.

    Yes, lazy is a callback function, it accepts a function t as an argument and returns a function that calls t.

    The local variable flag is used to keep track of whether the passed in lambda has been called. The lambda keeps its reference to the local variables even after the function they were declared in has completed, because it's a closure. Closures carry their environment where they were declared along with them as they're passed around the program, so flag and val effectively become private variables of the closure.

    The lambda returned by lazy is not a copy of anything, it's a new object getting created It can be called multiple times but makes sure the lambda t passed in is called only once. p will hold the function returned by calling lazy passing in the lambda wrapping the calls to display and returning "sig 3", this function is being passed in as the t in the definition of lazy.