Just how hard would it be to add a mutable toplevel language to Racket?

166 views
Skip to first unread message

Christopher Lemmer Webber

unread,
Mar 21, 2018, 1:49:15 PM3/21/18
to racket...@googlegroups.com
Just curious. I have my reasons... for instance, I wrote a multiplayer
game in Guile where you could change the world while players are in it
without kicking them out. I don't think you can do that while having a
toplevel that's as fixed as Racket's is.

I've read the emails from Matthew Flatt about "the toplevel is
hopeless". So the question is... how hard would it be to support
"#lang hopeless"? :) A language for the toplevel!

Maybe the toplevel is generally hopeless, but those of us who wish to
live in a world of despair can happily still have it.

Sam Tobin-Hochstadt

unread,
Mar 21, 2018, 1:51:20 PM3/21/18
to Christopher Lemmer Webber, racket users list
You might find the racket/load language useful for this.

Sam

--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Christopher Lemmer Webber

unread,
Mar 21, 2018, 2:16:43 PM3/21/18
to Sam Tobin-Hochstadt, racket users list
Hi Sam! I wasn't familiar with racket/load and it seems neat.
But it either seems too hopeless, or not hopeless enough:

Since all forms within a racket/load module are evaluated in the top
level, bindings cannot be exported from the module using provide.

This seems like a bit too much unfortunately. If I were to be writing
for instance a web application or a game or what have you, I'd still
want the dynamism of being able to redefine things, but I'd also want to
be able to export things from a module.

Maybe here's a properly hopeless level of indirection? What if we had
something like a lambda-box that for toplevel definitions of functions
instead wrapped the function in a box. It can still be invoked, but if
redefined, the contents of the box could be swapped out with a new
function? That's not too far off from how Guile's redefining works
presently, if I understand right. Redefining a toplevel non-function
could just set! the variable.

I guess maybe you couldn't provide more than what you've already
provided from the module. But that's probably okay?

Alexis King

unread,
Mar 21, 2018, 2:22:59 PM3/21/18
to Christopher Lemmer Webber, racket users list
I haven’t actually used it myself, but Tony Garnock-Jones’s
racket-reloadable library seems interesting and relevant.

https://github.com/tonyg/racket-reloadable

Alexis

> On Mar 21, 2018, at 11:16, Christopher Lemmer Webber

Philip McGrath

unread,
Mar 21, 2018, 2:57:02 PM3/21/18
to Christopher Lemmer Webber, Sam Tobin-Hochstadt, racket users list
You can already set! top level variables (or any variables) bound to functions.

$ racket
Welcome to Racket v6.12.
> (define (f) 1)
> (f)
1
> (set! f (lambda () 2))
> (f)
2


Alternatively, here is a little example of how you might define lambda-box:

#lang racket

(struct lambda-box ([proc #:mutable])
  #:property prop:procedure
  (make-keyword-procedure
   (λ (kws kw-args this . by-pos-args)
     (keyword-apply (lambda-box-proc this)
                    kws
                    kw-args
                    by-pos-args))))

(define f
  (lambda-box (λ () 1)))

(f)

(set-lambda-box-proc! f (λ () 2))

(f)


I guess my bigger question is whether making everything redefinable is really the best mechanism to achieve what you want. I would bet that, even in your example, you don't usually want to dynamically redefine cons or +. I think it would probably be better to be explicit about where you want to allow redefinition and where you want identifiers to refer to a specific binding.

If I were thinking about "a multiplayer game … where you could change the world while players are in it without kicking them out," I might think about a current-world parameter that can be mutated and having certain functions consult the current-world. Using the class-based object system or racket/generic for the world value might be particularly suitable. (Of course, the details would depend on exactly what about the world you want to be able to change.)


-Philip


>> For more options, visit https://groups.google.com/d/optout.
>>

--
You received this message because you are subscribed to the Google Groups "Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscribe@googlegroups.com.

Christopher Lemmer Webber

unread,
Mar 21, 2018, 5:26:38 PM3/21/18
to Philip McGrath, Sam Tobin-Hochstadt, racket users list
Philip McGrath writes:

> Alternatively, here is a little example of how you might define lambda-box:
>
> #lang racket
>
> (struct lambda-box ([proc #:mutable])
> #:property prop:procedure
> (make-keyword-procedure
> (λ (kws kw-args this . by-pos-args)
> (keyword-apply (lambda-box-proc this)
> kws
> kw-args
> by-pos-args))))
>
> (define f
> (lambda-box (λ () 1)))
>
> (f)
>
> (set-lambda-box-proc! f (λ () 2))
>
> (f)

Thanks! This is a very helpful.

I guess if used in combination with namespace-variable-value one could
extend or freshly define depending on whether or not things are
defined in (current-namespace).

> I guess my bigger question is whether making everything redefinable is
> really the best mechanism to achieve what you want. I would bet that, even
> in your example, you don't usually want to dynamically redefine cons or +.
> I think it would probably be better to be explicit about where you want to
> allow redefinition and where you want identifiers to refer to a specific
> binding.
>
> If I were thinking about "a multiplayer game … where you could change the
> world while players are in it without kicking them out," I might think
> about a current-world parameter that can be mutated and having certain
> functions consult the current-world. Using the class-based object system or
> racket/generic for the world value might be particularly suitable. (Of
> course, the details would depend on exactly what about the world you want
> to be able to change.)

It could be that there are per-instance ways to handle things. I'm
partly coming from the perspective of other lisps where there's a very
*general purpose* option with a mutable toplevel. It could be that in
various applications there may be a more *specific* options that are
better. But a lot of my question is whether or not the general route
*can* be brought to Racket. It looks like it can be, even if Racket
folks will in general not like it :)

> -Philip

Christopher Lemmer Webber

unread,
Mar 21, 2018, 5:27:56 PM3/21/18
to Alexis King, racket users list
Thanks kindly... Greg Hendershott pointed me at this before too. It may
be that in the cases where you do know in advance what layers need to be
more hackable and which don't that this is a good fit. It looks like it
would serve the webdev case well enough at least.
Reply all
Reply to author
Forward
0 new messages