[racket] Dynamic module loading

From: Evan Donahue (emdonahu at gmail.com)
Date: Wed Feb 5 15:20:40 EST 2014

It just struck me that my alias lang is structured a lot like #lang datalog
(accumulating assertions into a hidden theory). Sure enough, datalog seems,
on first glance, to handle some of the issues I'm facing. At the risk of
jynxing it, I think datalog can probably show me the rest of the way.

Thanks.


On Tue, Feb 4, 2014 at 11:22 PM, Evan Donahue <emdonahu at gmail.com> wrote:

> 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/20140205/827a9ab3/attachment-0001.html>

Posted on the users mailing list.