Section 4.3.3 (define (analyze-sequence exps) (define (sequentially a b) (lambda (env succeed fail) (a env ;; success continuation for calling a (lambda (a-value fail2) (b env succeed fail2)) ;; failure continuation for calling a fail))) (define (loop first-proc rest-procs) (if (null? rest-procs) first-proc (loop (sequentially first-proc (car rest-procs)) (cdr rest-procs)))) (let ((procs (map analyze exps))) (if (null? procs) (error "Empty sequence -- ANALYZE")) (loop (car procs) (cdr procs)))) The pattern in loop is really amazing. We have loop :: Proc → [Proc] → Proc, it proceeds by combining the first procedure with the first of the rest of them, and then recursing with that new procedure and the rest of the list. It's just like ordinary recursive list handling, but handling two elements at a time. I think the thing that strikes me as interesting is the way the first argument is used as an accumulator. --- I have found I read over the code in the text, but generally gain little understanding from doing so. To overcome this I am now trying the following technique: after reading a procedure (as the one above) if it is unfamiliar or non-obvious, I look away and rewrite it mentally, which forces me to understand the choices that have been made in writing it. This seems to be an effective way to read code for learning. --- A variation on the above is to write the code mentally before reading it, which is what I did in the case of the following from the same section: (define (analyze-assignment exp) (let ((var (assignment-variable exp)) (vproc (analyze (assignment-value exp)))) (lambda (env succeed fail) (vproc env (lambda (val fail2) ; *1* (let ((old-value (lookup-variable-value var env))) (set-variable-value! var val env) (succeed 'ok (lambda () ; *2* (set-variable-value! var old-value env) (fail2))))) fail))))