Hi all - <br><br>As promised, below is my summary from studying this problem - hopefully someone else learning scheme will find it useful ;) <br><br>The basic goal was to have a system that can allow for duplicate define expressions within modules. There are two identified behaviors:
<span style="font-weight: bold;">define-once </span>(subsequent defines are ignored), or <span style="font-weight: bold;">define-over </span>(subsequent define overwrite the previous definition). <br><br>The method to recognize whether a variable has been defined is via
<span style="font-weight: bold;">identifier-binding</span> (<a href="http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017423.html">http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017423.html</a>). If it returns anything other than 'lexical or null, then it has a top level binding; but imported versus locally defined are separated (I later found out that an imported binding doesn't get expanded to (#%top . binding) during expansion -
<a href="http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017465.html">http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017465.html</a>). <br><br>The difference between define-once and define-over basically amounts to what to do when a binding is identified: define-once expands to (void) whereas define-over expands to (set! var exp), but without additional help, neither works across modules.
<br><br>define-once: doesn't provide the variable in the requiring module <br><br>(module foo mzscheme <br> (define-once x 1)<br> (define-once x 2) ; (void) ignored<br> (provide (all-defined))) <br><br>(module bar mzscheme
<br> (require foo) <br> (define-once x 3) ; (void) ignored too <br> (provide (all-defined))) ; provide nothing. <br><br>define-over: cannot define the variable again in the requiring module <br><br>(module foo mzscheme
<br> (define-over x 1) <br> (define-over x 2) ; (set! x 2) <br> (provide (all-defined))) <br>(module bar mzscheme <br> (require foo) <br> (define-over x 3)) ; error - cannot mutate module required variable: x<br> <br>
The problem with define-once is easier to solve: with the help of bookkeeping (<a href="http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017423.html">http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017423.html
</a>) - one can distinguish between whether a module has been imported vs locally defined, and if it has only been imported once or twice. If just the first time, then (provide var), else (void). <br><br>The problem with define-over is harder to solve because of the way module is designed (
i.e. the boundary is fixed). The easiest way that I know is to prefix the module import, figure out what have been imported, and alias them, e.g., <br><br>(require (prefix foo: foo)) <br>(define x foo:x) ; alias <br><br>
Creating an prefix is straight forward as it can based on the module spec, which is "unique" for the module system. <br><br>Figuring out where the module actually lives (in the file system, not in REPL) require the use of (current-module-name-resolver), which returns a symbol that basically maps to the file path of the module. Translating it back to path is straight forward.
<br><br>With the actual module path one can utilize the method from <a href="http://list.cs.brown.edu/pipermail/plt-scheme/2003-November/003698.html">http://list.cs.brown.edu/pipermail/plt-scheme/2003-November/003698.html
</a> to extract the variables. Prepend the variables with the prefix, and generate the (define var prefix:var) form for expansion. <br><br>The rest is to create the macro to expand to the above form - <a href="http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017475.html">
http://list.cs.brown.edu/pipermail/plt-scheme/2007-April/017475.html</a><br><br>This solution, of course, equates to evaluating the required modules twice, which is probably not something that should be done without thinking. There could be a way to automatically retrieve the list of exported variables but I don't know that at the moment, and it's time to solve other problems ;)
<br><br>Thanks to all for help again, <br>yinso <br><br><div><span class="gmail_quote">On 4/22/07, <b class="gmail_sendername">Yin-So Chen</b> <<a href="mailto:yinso.chen@gmail.com">yinso.chen@gmail.com</a>> wrote:</span>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Hi all - <br><br>Just want to thank everyone (Jos, Matthew, Jens, and Eli) for providing the pointers - this is awesome help. I will study the different methods and will definitely report back on my take aways ;)
<br><br>Very appreciated. Thanks,
<br>yinso <div><span class="e" id="q_1121cdcecf6cdf7d_1"><br><br><div><span class="gmail_quote">On 4/22/07, <b class="gmail_sendername">Eli Barzilay</b> <<a href="mailto:eli@barzilay.org" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">
eli@barzilay.org</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
On Apr 22, Matthew Flatt wrote:<br>> At Sun, 22 Apr 2007 03:32:36 -0700, "Yin-So Chen" wrote:<br>> > My motivation for having a conditional define is to make it play<br>> > nice with the module system, which doesn't work well when having
<br>> > multiple definitions with the same name. I was hoping there is an<br>> > "automated" way of detecting whether a symbol is already defined<br>> > in the current module, if so, either override or not import the
<br>> > definition.<br>><br>> Within a module, `identifier-binding' should do the trick.<br><br>Funny that this came right after the Swindle question -- they're<br>related. When you use `defmethod' Swindle is trying to guess whether
<br>you're defining a new method, or adding to an existing one. See the<br>code in "collects/swindle/clos.ss" (look for `identifier-binding') for<br>how it's done -- my guess is that you'll want something similar.
<br><br>BUT -- having gone through that, I can tell you that you will need a<br>lot of fighting to get things right. It's a question whether it's<br>worth it. (In other words -- I often think that I should have not
<br>included a `defmethod' -- it's much cleaner to have only `defgeneric'<br>and `add-method'.)<br><br>--<br> ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:<br> <a href="http://www.barzilay.org/" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">
http://www.barzilay.org/</a> Maze is Life!<br></blockquote></div><br><br clear="all"><br></span></div><div><span class="e" id="q_1121cdcecf6cdf7d_2">-- <br><a href="http://www.yinsochen.com" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">
http://www.yinsochen.com</a><br>...continuous learning...
</span></div></blockquote></div><br><br clear="all"><br>-- <br><a href="http://www.yinsochen.com">http://www.yinsochen.com</a><br>...continuous learning...