[racket] Fresh sandboxes in Scribble documentation (was: Typed macros in untyped code)

From: Neil Toronto (neil.toronto at gmail.com)
Date: Fri Nov 19 15:03:20 EST 2010

Sam Tobin-Hochstadt wrote:
> On Thu, Nov 18, 2010 at 7:48 PM, Neil Toronto <neil.toronto at gmail.com> wrote:
>> But Typed Racket craps on me if I use the typed macros inside a sandbox in
>> Scribble. For example, using @(example #:eval my-eval (bftest-error (bfexp
>> (bf 2)))) gives me this:
>>
>>> (bftest-error (bfexp (bf 2)))
>>  eval:63:0: Type Checker: Macro bftest-error from typed
>>  module used in untyped code in: (bftest-error (bfexp (bf
>>  2)))
>>
>> Gah! I thought I got around this! How do I convince Typed Racket or the
>> sandbox that I'm not up to anything funny?
> 
> Require `#%top-interaction' from typed racket, or in general create
> your sandbox from Typed Racket.

Okay, I got that working by copying from ts-guide.scrbl. I like having 
the types printed in the examples. Nice.

Now I have another problem: I can't redefine anything inside the 
sandbox. I use consistent names for the same types of objects, so this 
is a problem from a pedagogical point of view.

But it's not TR's fault, hence the subject change. By disallowing 
redefinition, TR is actually exposing a problem in how we usually write 
documentation that contains examples.

The problem: because we create one evaluator and use it for everything, 
our documentation examples aren't independent. They can change each 
other's execution environments. Anything that has a computational effect 
can do that: using set!, setting parameters, or even *defining a variable*.

All of my examples set a parameter. If I used `parameterize' instead, 
they'd all look like this:

     @(examples #:eval bigfloat-eval
                (parameterize ([bf-bits  ...])
                  <some-computation>)
                (parameterize ([bf-bits  ...])
                  <some-computation>)
                ...)

I can't combine them all under one `parameterize' because I'd lose the 
REPL-like interaction. But as it is, I can't reorder my examples or 
`defproc's without thinking seriously about the effect they'll have on 
each other.

So I tried to solve the independent-examples problem by creating a fresh 
evaluator for each example. When I tried to run it, it took forever. And 
then it ran out of memory and DrRacket asked for more.

Currently, I only create a new evaluator for *specific* examples that 
have certain effects, but this won't scale. Question for the group: is 
there a better way to isolate examples? I've got a voodoo half-idea that 
I can branch the original evaluator using continuations, but I don't 
know how.

Neil T


Posted on the users mailing list.