[racket-dev] Diagnosing traverse-block errors in scribble

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Thu Jun 27 08:18:32 EDT 2013

At Wed, 26 Jun 2013 16:19:55 -0400, Kathi Fisler wrote:
> As I understand traverse-block, the number of (lambda (get set) ...)
> wrappers is what helps stage the passes.  So if I want to generate data in
> the first pass, I need one lambda, but to use that in second pass I need
> two lambdas.  Is that the right intuition?

That's right.

In the code you posted last week, 

  (define (glossary)
    (traverse-block
     (lambda (get set)
       (traverse-block
         (lambda (get set)
           (define terms (get 'vocab-used '()))
           (para terms))))))

the `traverse-block' is are not useful. The inner `lambda' needs to be
exposed directly to make it happen on the next iteration.

At the end of this message is an example showing nested `lambda's.

But I bet the path to solving your problem is to use the "collect" and
"resolve" passes, instead.


At Wed, 26 Jun 2013 16:19:55 -0400, Kathi Fisler wrote:
> I keep getting an error "traverse-block-block: no block computed for
> traverse-block", and am trying to understand how to interpret this.

The error means that a particular traverse block was discovered for the
first time after the traverse pass. For example, if a `delayed-block'
generates a `traverse-block', then it will trigger the error, because
`delayed-block's are not triggered until the "resolve" pass:

 (delayed-block
  (lambda (r p ri)
   (traverse-block (lambda (get set) (para "won't get here")))))


Maybe you're using your glossary forms in something that delays until a
resolve pass? But, then, I can't explain why you see the error only
when using nested `lambda's in a `traverse-block'.

If I'm on the right track, anyway, then for something like a glossary,
you can probably use the "collect" and "resolve" passes, instead of the
"traverse" pass. That way, your glossary construction will work nicely
with other things that happen at the collect and resolve passes.

----------------------------------------

#lang scribble/base
@(require scribble/core)

@(traverse-element
  (lambda (get set)
   ;; Not delayed, and so result is "not ready, yet"
   (get 'glossary "not ready, yet")))

@(traverse-element
  (lambda (get set)
   ;; Delayed until second traversal:
   (lambda (get set)
    (get 'glossary "BROKEN"))))

@; Same thing, but with blocks:

@(traverse-block
  (lambda (get set)
    ;; Not delayed:
    (para "The glossary is " 
          (get 'glossary "not ready, yet"))))

@(traverse-block
  (lambda (get set)
    ;; Delayed:
    (lambda (get set)
      (para "The glossary is " 
            (get 'glossary "BROKEN")))))

@(traverse-block
  (lambda (get set)
    ;; Adding a `delayed-block' doesn't delay:
    (traverse-block
      (lambda (get set)
        (para "The glossary is "
              (get 'glossary "not ready, yet"))))))

@(traverse-block
  (lambda (get set)
    (set 'glossary "ready")
    (para "Here is the glossary.")))


Posted on the dev mailing list.