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

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Fri Nov 19 15:18:48 EST 2010

Neil,

Check out make-eval-factory and make-base-eval-factory in
scribble/eval.  They let you create new evaluators that nevertheless
share compiled versions of the modules you are using.  That way you
don't recompile your language and instantiate new modules at each
example.  It's not super fast -- you still create a new store and so
on -- but it should be faster than the naive version that creates
completely new namespaces.

Carl Eastlund

On Fri, Nov 19, 2010 at 3:03 PM, Neil Toronto <neil.toronto at gmail.com> wrote:
> 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.