[racket] Dynamic module loading

From: Evan Donahue (emdonahu at gmail.com)
Date: Wed Feb 5 02:22:39 EST 2014

Thanks for the response. The dynamic-require + rerequire seems to handle
that issue, and with the addition of some module-begin code I have
successfully hidden the construction of the hash from the end user. There
is just one more item on my desiderata that seems to be stumping me, the
general statement of which is: how do I preserve provide/require
functionality when defining a new #lang

I have structured my module-begin after the fashion of fudging up a racket.
Specifically, in my lang file:

(provide alias)

(define aliases (make-parameter #f))

(define-syntax-rules (alias a b)
   (hash-set! (aliases/param) 'a 'b)))

#`(#%plain-module-begin
        (provide aliases)
        (define aliases (make-hash))
        (parameterize ([aliases/param aliases])
          body ...))


This works great for one module, but should I like to require additional
modules in my alias file to help with alias construction (or provide things
defined in one alias file to another), I end up with an expansion like

(parameterize ([...])
   (require ...

and receive the error "require not at module level"

My question, then, is what might be a better way to structure a lang ifle +
module-begin to preserve require/provide functionality while also achieving
the encapsulation of state achieved in the fudging up a racket tutorial?

Thank you,
Evan


On Fri, Jan 31, 2014 at 4:35 AM, Jay McCarthy <jay.mccarthy at gmail.com>wrote:

> Hi Evan,
>
> Your alias file is like a function with the type (-> Void) because it
> is run only for its effect and its effect is only to "add", which
> makes it impossible to "subtract". One way to solve this is to change
> its type to (-> Hash) so that it returns what the hash should be. For
> instance,
>
> (define alias-ht (make-hash)) ;; common.rkt
> (for (...) (hash-set! alias-ht ...)) ;; user-input.rkt
> (dynamic-rerequire "user-input.rkt") ;; server.rkt
> (hash-ref alias-ht ...) ;; server.rkt
>
> is like what you have. But you could change it to
>
> (define alias-ht (for/hash (...) ...)) ;; user-input.rkt
> (define alias-ht (make-hash)) ;; server.rkt
>  ;; server.rkt
> (begin (dynamic-rerequire "user-input.rkt")
>            (set! alias-ht (dynamic-require "user-input.rkt" 'alias-ht)))
> (hash-ref alias-ht ...) ;; server.rkt
>
> so that after you attempt to reload, then you pull out the 'alias-ht
> value from either the new or old version of the module
>
> Jay
>
>
> On Fri, Jan 31, 2014 at 3:37 AM, Evan Donahue <emdonahu at gmail.com> wrote:
> > Hello. I've been trying to get a particular use case for module loading
> to
> > work, and, while I have a mostly functional solution, I am unsure
> whether I
> > am using the best infrastructure for the task. The explanation is a bit
> > involved, but the basic question is what is the right way to update a
> > running system using values generated by racket code (update as in feed
> new
> > data to, not reload the module bindings of).
> >
> > I have a text-based game client that needs to be able to dynamically load
> > user-defined aliases while running. Ordinarily this could be solved by
> > simply reading a file of alias definitions and updating the structure in
> > memory. However, as the alias system may potentially be quite complex, I
> was
> > hoping to use both the racket language and module system to define these
> > aliases. Ie, I might have inventory-aliases.rkt, which requires
> > item-aliases.rkt in order to reuse helper code defined in the latter in
> the
> > former.
> >
> > My current solution involves having all alias code as well as the main
> > program require a common base.rkt that provides a single aliases #hash.
> Each
> > alias file, when loaded, destructively sets all its aliases into the
> hash,
> > which are in turn usable by the main program.
> >
> > When a user updates an alias file, I dynamic-rerequire the file, which,
> > since the hash set!s are idempotent, mostly works. The trouble is that
> if a
> > user deletes an alias, I do not know to get rid of it in my hash
> structure.
> > Moreover, I cannot throw out the hash because dynamic-rerequire only
> reruns
> > changed modules.
> >
> > Before I continue on down this rabbit hole and start adjusting
> timestamps to
> > have dynamic-rerequire do what I need it to do, I wanted to ask whether
> > there was a more canonical way to achieve my ends. I get the impression
> that
> > I am somewhat hijacking the module system since I am mostly using it to
> > structure the alias code, but then am trying to extract something that is
> > not quite an exported set of values from it. Would it make sense perhaps
> to
> > construct an evaluator out of the alias definitions and evaluate user
> inputs
> > in that language? I am not intimately familiar with the module system,
> and
> > so am doing a bit of a random walk around its infrastructure as I learn
> more
> > about it.
> >
> > I sense this question may be a bit obscure, so thank you in advance to
> > anyone who has any insights to share on the matter.
> >
> > Evan
> >
> > ____________________
> >   Racket Users list:
> >   http://lists.racket-lang.org/users
> >
>
>
>
> --
> Jay McCarthy <jay at cs.byu.edu>
> Assistant Professor / Brigham Young University
> http://faculty.cs.byu.edu/~jay
>
> "The glory of God is Intelligence" - D&C 93
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20140204/56b5df8d/attachment.html>

Posted on the users mailing list.