Exercises in this lecture  previous -- Keyboard shortcut: 'p'        Go to the slide, where this exercise belongs -- Keyboard shortcut: 'u'  

Exercise 3.6
A variant of seesaw that completes both threads ***


The function seesaw, as discussed on the slide, only completes one of the threads. This may be convenient in some situations (if one of the threads runs infinitly), but in general we are interested in the results of both threads. Here is the version of seesaw that we discuss:

  (define (seesaw thread-1 thread-2)                           
    (cond ((eqv? 'done (tag-of thread-1))                      
            (tag-value thread-1))
          ((eqv? 'doing (tag-of thread-1))
            (seesaw thread-2 (call (tag-value thread-1))))))

Program a version of seesaw that - at the very end - return a list of length 2: First element must be the value finally returned by thread-1, and the second element must be the value finally returned by thread-2. Here is an example of the call of the new version of seesaw:

  > (seesaw (fact-iter 5 1) (fib 8))
  (120 21)

Your variant of seesaw may be seen as an example of a loop which maintains some state (the two threads, their status (doing/done), and their values - if they exist). As such, this exercise is a good example of programming an iterative, tail-recursive, state-transitioning function in Scheme.

  

Here is all you need to get started:


(define (return x) (tag 'done x))                 
(define (bounce thunk) (tag 'doing thunk))   
(define (call thunk) (thunk))    
(define (tag label thing) (cons label thing))
(define tag-of car)
(define tag-value cdr)

(define (fact-iter n acc)
  (if (zero? n)
      (return acc)
      (bounce 
        (lambda ()
          (fact-iter
            (- n 1)
            (* acc n))))))

(define (mem? n lst)
  (cond ((null? lst) (return #f))
        ((= (car lst ) n) (return #t))
        (else (bounce
                (lambda ()
                  (mem? n (cdr lst)))))))

(define (fib n)
  (fib-iter n 0 0 1))

(define (fib-iter n i small large)
  (if (< i n)
      (bounce
        (lambda () 
          (fib-iter n (+ i 1) large (+ large small))))
      (return small)))

(define (pogo-stick thread)                                  
  (cond ((eqv? 'done (tag-of thread))                      
          (tag-value thread))                                
        ((eqv? 'doing (tag-of thread))                     
          (pogo-stick (call (tag-value thread))))))          

; A version of seesaw that delivers 'the value of the fastest thread'.
; The one from the video.
(define (seesaw thread-1 thread-2)                           
  (cond ((eqv? 'done (tag-of thread-1))                      
          (tag-value thread-1))
        ((eqv? 'doing (tag-of thread-1))
          (seesaw thread-2 (call (tag-value thread-1)))))) 


Solution