<div>Hi Nick,</div><div><br></div>2013/8/4 Nick Sivo <span dir="ltr">&lt;<a href="mailto:nicksivo@gmail.com" target="_blank">nicksivo@gmail.com</a>&gt;</span><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

I&#39;d like to make Arc work as a Racket language (and in the process<br>
preserve srclocs and names), and have made some progress[4].  However,<br>
I&#39;m hitting a wall trying to implement Arc&#39;s macros.  Specifically, I<br>
need to find a way for the macros themselves to use previously defined<br>
Arc functions as part of their processing. I understand that there are<br>
good reasons for Racket&#39;s hygiene and syntax phases, but I&#39;m<br>
implementing an existing language that has its own strong opinions.<br>
I&#39;m almost certain that accomplishing my goal is possible with the<br>
right understanding, but despite reading much of the Racket Reference,<br>
I don&#39;t truly get it yet.<br></blockquote><div><br></div><div>The evaluation model of Arc makes it hard to device a general solution. The problem is that arc-identifiers are represented</div><div>as symbols which do not contain any source location information.</div>
<div><br></div><div>For a macro like this:</div><div><pre style="word-wrap:break-word;white-space:pre-wrap">    (mac when (test . body)
       (list &#39;if test (cons &#39;do body)))</pre><pre style="word-wrap:break-word;white-space:pre-wrap"><span style="font-family:arial;white-space:normal">which defines a when macro that expands </span></pre><pre style="word-wrap:break-word;white-space:pre-wrap">
<span style="font-family:arial;white-space:normal">   (when test body ...) to (if test (do body ...))</span></pre><pre style="word-wrap:break-word;white-space:pre-wrap"><span style="font-family:arial">you know the source location of the identifier when.</span></pre>
<pre style="word-wrap:break-word;white-space:pre-wrap"><br></pre><pre style="word-wrap:break-word;white-space:pre-wrap"><font face="arial">However if you have a arc-macro that expands to into a new</font></pre><pre style="word-wrap:break-word;white-space:pre-wrap">
<font face="arial">arc-macro definition, the arc programmer has no way of</font></pre><pre style="word-wrap:break-word;white-space:pre-wrap"><font face="arial">attaching source location information to the generated</font></pre>
<pre style="word-wrap:break-word;white-space:pre-wrap"><font face="arial">arc-identifer.</font></pre><pre style="word-wrap:break-word;white-space:pre-wrap"><font face="arial"><br></font></pre><pre style="word-wrap:break-word;white-space:pre-wrap">
<font face="arial">That said an 80% solution is better than nothing.</font></pre><pre style="word-wrap:break-word;white-space:pre-wrap"><span style="font-family:arial"> </span></pre></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

With that motivation in mind, what&#39;s the best way for me to become<br>
intimately familiar with Racket&#39;s runtime, execution and compilation<br>
model? Should I read through and make sure I understand the debugger?<br>
The macro stepper?  Is there any kind of guide to Racket Internals?<br></blockquote><div><br></div><div>I would read up on modules (and submodules) and experiment</div><div>with define-syntax and begin-for-syntax. Skip the debugger.</div>
<div><br></div><div>Given the way Arc mixes the phases it is hard to compile Arc to anything. </div><div><div>Consider for example how you would compile Arc-with-macros </div><div>into Arc-without-macros. </div></div><div>
<br></div><div>If I understand the evaluation model correctly, then you basically can&#39;t</div><div>compile an Arc program without running it. If you assume that certain</div><div>names aren&#39;t redefined (such as if, mac and others) then it might</div>
<div>be possible to compile parts.</div><div><br></div><div>&gt; Specifically, I need to find a way for the macros themselves to use </div><div>&gt; previously defined Arc functions as part of their processing. </div><div>
<br></div><div>Here is a few examples that illustrate how to make a function</div><div>available both in runtime (phase 0) and at compile time (here in phase 1).</div><div><br></div><div>The idea of the final example is to compile (read arc-definitions) definitions</div>
<div>into submodule, which are then required in both phases. This implies</div><div>that the code is run twice...</div><div><br></div><div>/Jens Axel Søgaard</div><div><br></div><div><br></div><div><div>#lang racket</div>
<div><br></div><div>; Let us define a simple macro myand and use it as</div><div>; a running example.</div><div><br></div><div>(module ex1 racket</div><div>  (define-syntax (myand stx)</div><div>    (syntax-case stx ()</div>
<div>      [(_)                 #&#39;#t]</div><div>      [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)]))</div><div>  </div><div>  ; Test it:</div><div>  (displayln &quot;Example 1&quot;)</div><div>  (myand (= 1 1) (= 2 3))  ; =&gt; #f</div>
<div>  (myand (= 1 1) (= 2 2))  ; =&gt; #t</div><div>  ; Conclusion: It works on runtime.</div><div>  )</div><div><br></div><div>; Now can we use in a macro (at expansion time?)</div><div><br></div><div>#;(module ex2 racket</div>
<div>    (define-syntax (myand stx)</div><div>      (syntax-case stx ()</div><div>        [(_)                 #&#39;#t]</div><div>        [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)]))</div><div>    </div><div>
    (define-syntax (macro-that-uses-myand stx)</div><div>      (syntax-case stx ()</div><div>        [(_ x y z) </div><div>         (if (myand (= 1 1))      ; &lt;= this myand gives the error below</div><div>             #&#39;&#39;one-equals-one</div>
<div>             #&#39;&#39;huh?)])))</div><div><br></div><div>; Nope. The example ex2 gives the error:</div><div>;     myand: unbound identifier in module (in the transformer environment, </div><div>;     which does not include the macro definition that is visible to run-time </div>
<div>;     expressions) in: myand</div><div><br></div><div>; In order to make it visible, we need to define it both in the runtime</div><div>; and transformer environment.</div><div><br></div><div>(module ex3 racket</div>
<div>  (define-syntax (myand stx)</div><div>      (syntax-case stx ()</div><div>        [(_)                 #&#39;#t]</div><div>        [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)]))</div><div>  (begin-for-syntax</div>
<div>    (require (for-syntax racket))</div><div>    (define-syntax (myand stx)</div><div>      (syntax-case stx ()</div><div>        [(_)                 #&#39;#t]</div><div>        [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)])))</div>
<div>  (define-syntax (macro-that-uses-myand stx)</div><div>    (syntax-case stx ()</div><div>      [(_ x y z) </div><div>       (if (myand (= 1 1))</div><div>           #&#39;&#39;one-equals-one</div><div>           #&#39;&#39;huh?)]))  </div>
<div>  (displayln &quot;Example 3&quot;)  </div><div>  (macro-that-uses-myand 1 2 3)</div><div>  (myand (= 1 1) (= 2 3)))</div><div><br></div><div>; Writing the same macro twice is a bad idea, so we&#39;ll let</div><div>; a macro do the job.</div>
<div><br></div><div>(module define*-mod racket</div><div>  (provide define*)</div><div><br></div><div>  (define-syntax (define* stx)</div><div>    (syntax-case stx ()</div><div>      [(_ macro-definition)</div><div>       #&#39;(begin</div>
<div>           (begin-for-syntax macro-definition)</div><div>           macro-definition)])))</div><div><br></div><div>; Let&#39;s test the macro:</div><div><br></div><div>(module ex4 racket</div><div>  (require (submod &quot;..&quot; define*-mod)</div>
<div>           (for-syntax (for-syntax racket))) ; make syntax-case available in phase 2</div><div>  (define*</div><div>    (define-syntax (myand stx)</div><div>      (syntax-case stx ()</div><div>        [(_)                 #&#39;#t]</div>
<div>        [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)])))</div><div>  (define-syntax (macro-that-uses-myand stx)</div><div>    (syntax-case stx ()</div><div>      [(_ x y z) </div><div>       (if (myand (= 1 1))</div>
<div>           #&#39;&#39;one-equals-one</div><div>           #&#39;&#39;huh?)]))  </div><div>  (displayln &quot;Example 4&quot;)</div><div>  (macro-that-uses-myand 1 2 3)</div><div>  (myand (= 1 1) (= 2 3)))</div><div><br>
</div><div>; This works, but in general code duplication is a Bad Thing (TM).</div><div>; If we place the definition of myand in a module, we can import it</div><div>; in both phases.</div><div><br></div><div>(module ex5 racket</div>
<div>  ; A submodule containing a definition of myand:</div><div>  (module myand-mod racket</div><div>    (provide myand)</div><div>    (define-syntax (myand stx)</div><div>      (syntax-case stx ()</div><div>        [(_)                 #&#39;#t]</div>
<div>        [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)])))</div><div>  </div><div>  ; Import it in both phases:</div><div>  (require             (submod &quot;.&quot; myand-mod)</div><div>           (for-syntax (submod &quot;.&quot; myand-mod)))</div>
<div>  ; Test it:</div><div>  (define-syntax (macro-that-uses-myand stx)</div><div>    (syntax-case stx ()</div><div>      [(_ x y z) </div><div>       (if (myand (= 1 1))</div><div>           #&#39;&#39;one-equals-one</div>
<div>           #&#39;&#39;huh?)]))  </div><div>  (displayln &quot;Example 5&quot;)</div><div>  (macro-that-uses-myand 1 2 3)</div><div>  (myand (= 1 1) (= 2 3)))</div><div><br></div><div>; Now let&#39;s write a macro that can generate the submodule automatically.</div>
<div><br></div><div>(module define/mod-mod racket</div><div>  (provide define/mod)</div><div>  (define-syntax (define/mod stx)</div><div>    (syntax-case stx ()</div><div>      [(_ name definition)</div><div>       #&#39;(begin</div>
<div>           (module name racket</div><div>             (provide name)</div><div>             definition)</div><div>           #;(require (submod &quot;.&quot; name) (for-syntax (submod &quot;.&quot; name)))   ; footnote *</div>
<div>           )])))</div><div><br></div><div>(module ex6 racket</div><div>  (require (submod &quot;..&quot; define/mod-mod))</div><div>  (define/mod myand </div><div>    (define-syntax (myand stx)</div><div>      (syntax-case stx ()</div>
<div>        [(_)                 #&#39;#t]</div><div>        [(_ expr0 expr ...)  #&#39;(if expr0 (myand expr ...) #f)])))</div><div>  (require (submod &quot;.&quot; myand) (for-syntax (submod &quot;.&quot; myand)))           ; footnote **</div>
<div>  ; Test it:</div><div>  (define-syntax (macro-that-uses-myand stx)</div><div>    (syntax-case stx ()</div><div>      [(_ x y z) </div><div>       (if (myand (= 1 1))</div><div>           #&#39;&#39;one-equals-one</div>
<div>           #&#39;&#39;huh?)]))  </div><div>  (displayln &quot;Example 6&quot;)</div><div>  (macro-that-uses-myand 1 2 3)</div><div>  (myand (= 1 1) (= 2 3)))</div><div><br></div><div>; Ideally the line marked ** could be commented out and the one marked * be used instead.</div>
<div>; If I remember correctly I need to do *something* with the require, but what ...</div><div><br></div><div>(require &#39;ex1)</div><div>(require &#39;ex3)</div><div>(require &#39;ex4)</div><div>(require &#39;ex5)</div>
<div>(require &#39;ex6)</div><div><br></div></div><div><br></div><div><br></div><div><br></div><div><br></div></div>