<div dir="ltr">Sorry, gmail sent before I could paste :(<div><br></div><div>...</div><div><br></div><div>So I changed the macro definition to:</div><div><br></div><div><div>(define-syntax (define/spec stx)</div><div> (syntax-parse stx</div>
<div><span class="" style="white-space:pre"> </span>[(_ (proc:id arg:expr ...)</div><div><span class="" style="white-space:pre"> </span>body:expr ...</div><div><span class="" style="white-space:pre"> </span>#:doc contract:expr arg-spec:expr desc:expr</div>
<div><span class="" style="white-space:pre"> </span>#:test test-body:expr ...)</div><div><span class="" style="white-space:pre"> </span> (with-syntax ([id-str (symbol->string (syntax->datum #'proc))]</div><div>
<span class="" style="white-space:pre"> </span> [ru-require (format-id stx "~a" "rackunit")])</div><div><span class="" style="white-space:pre"> </span> #'(begin</div><div><span class="" style="white-space:pre"> </span> (provide</div>
<div><span class="" style="white-space:pre"> </span>(proc-doc/names proc contract arg-spec desc))</div><div><span class="" style="white-space:pre"> </span> (define (proc arg ...) body ...)</div><div><span class="" style="white-space:pre"> </span> (module+ test</div>
<div><span class="" style="white-space:pre"> </span> (require ru-require)</div><div><span class="" style="white-space:pre"> </span> (require rackunit)</div><div><span class="" style="white-space:pre"> </span> (test-case id-str test-body ...))))]))</div>
</div><div><br></div><div>Notice the extra (require rackunit), after the modified (require ru-require). Is that the right solution?</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Wed, Jan 8, 2014 at 4:00 PM, Carl Eastlund <span dir="ltr"><<a href="mailto:carl.eastlund@gmail.com" target="_blank">carl.eastlund@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="im">On Wed, Jan 8, 2014 at 6:44 PM, Scott Klarenbach <span dir="ltr"><<a href="mailto:scott@pointyhat.ca" target="_blank">scott@pointyhat.ca</a>></span> wrote:<br>
</div><div class="gmail_extra"><div class="gmail_quote"><div class="im">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Thanks guys.<div><br></div><div>I changed it to this:</div><div><br></div><div><div>
<div>(define-syntax (define/test stx)</div><div> (syntax-parse stx</div></div><div><span style="white-space:pre-wrap"> </span>[(_ (proc:id arg:expr ...)</div>
<div><span style="white-space:pre-wrap"> </span>body:expr ...</div><div><span style="white-space:pre-wrap"> </span>#:test test-body:expr ...)</div><div><span style="white-space:pre-wrap"> </span> (with-syntax ([id-str (symbol->string (syntax->datum #'proc))]</div>
<div><span style="white-space:pre-wrap"> </span>[ru-require (format-id stx "~a" "rackunit")])</div><div><span style="white-space:pre-wrap"> </span> #'(begin</div><div><span style="white-space:pre-wrap"> </span> (define (proc arg ...) body ...)</div>
<div><span style="white-space:pre-wrap"> </span> (module+ test</div><div><span style="white-space:pre-wrap"> </span> (require ru-require)</div><div><div><span style="white-space:pre-wrap"> </span> (test-case id-str test-body ...))))]))</div>
</div></div><div><br></div><div>and it works now. Is that what you meant Carl?</div></div></blockquote><div><br></div></div><div>Yep, that's it.<br></div><div class="im"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr"><div><div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<span style="font-family:arial,sans-serif;font-size:13px">The problem is that check-true (and check-false) are not in scope (as<br></span><span style="font-family:arial,sans-serif;font-size:13px">you discovered) during expansion.</span></blockquote>
<div><br></div></div><div>I'm still a bit confused as to why. I figured the (require rackunit) would have brought check-true into scope during expansion, much the same as if I just copied the (begin... form into another file without the macro.</div>
<div></div></div></blockquote><div><br></div></div><div>The (require rackunit) does bring the names into scope... but _which_ scope? That's always the important question with macros. By default, a binding form brings names into the scope in which the binding occurrence of the names are written. That's why if you write a local binding inside a macro definition, only the code inside the macro can see it, while if you bind a name that the user passed in, the user can see it.<br>
<br></div><div>With require, neither party writes the name; the name shows up in the module definition. Therefore, the require form has to figure out what scope to bind the names in some other way. So, for module names at least, require uses the scope in which the module name is written to bind all of the definitions provided by the module. (Things get more interesting if you use prefix-in or other import forms; they each have their own rules.)<br>
<br></div><div>In your example, what scope was the module name rackunit written in? Inside the macro definition. That's why writing #'(let ([check-true <stuff>]) body ...) and#'(begin (require rackunit) body ...) both make check-true visible only inside the macro definition. To make check-true visible to the macro user, you have to change the context of the name check-true. In the first case, that means changing the context of the identifier check-true; in the second, it means changing the context of the module name rackunit.<br>
<br></div><div>So when things go wrong with macro bindings, the first question is always "_which_ scope is this bound in?" and usually the second is "well, what context does the binding occurrence have?".<br>
<br></div><div>I hope that helps, these are really murky waters, so if you're confused, you're definitely not alone. We're happy to ask questions frequently and in detail.<br><br>Good luck!<br></div><div><div class="h5">
<div> </div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"> On Wed, Jan 8, 2014 at 2:37 PM, Carl Eastlund <span dir="ltr"><<a href="mailto:carl.eastlund@gmail.com" target="_blank">carl.eastlund@gmail.com</a>></span> wrote:<br>
<div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><p dir="ltr">I do not suggest rebinding the whole body like that; it could be seriously problematic if the user refers to something not viable to the macro definition. What you need to rebind is the name "rackunit" itself passed to require so that it has the context of the macro application. That way the names bound by the require will be visible to the macro user.</p>
<div><div>
<div class="gmail_quote">On Jan 8, 2014 5:29 PM, "Stephen Chang" <<a href="mailto:stchang@ccs.neu.edu" target="_blank">stchang@ccs.neu.edu</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
The problem is that check-true (and check-false) are not in scope (as<br>
you discovered) during expansion. Here is one way to fix your problem<br>
by recapturing the test expressions to have the proper context. You<br>
can also use syntax-local-introduce instead of the lambda (someone<br>
correct me if this is not proper usage).<br>
<br>
#lang racket<br>
(require (for-syntax syntax/parse))<br>
<br>
(define-syntax (define/test stx)<br>
(syntax-parse stx<br>
[(_ (id arg ...) body ... #:test test-body ...)<br>
(with-syntax ([id-str (symbol->string (syntax->datum #'id))]<br>
[(new-test-body ...)<br>
(map<br>
(λ (s) (datum->syntax #'here (syntax->datum s)))<br>
(syntax->list #'(test-body ...)))])<br>
#'(begin<br>
(define (id arg ...) body ...)<br>
(print id-str)<br>
(module+ test<br>
(require rackunit)<br>
(test-case id-str<br>
new-test-body ...))))]))<br>
<br>
(define/test (my-fn a b c)<br>
(print a)<br>
(print b)<br>
(print c)<br>
#:test<br>
(check-true #t)<br>
(check-false #t))<br>
<br>
On Wed, Jan 8, 2014 at 4:53 PM, Scott Klarenbach <<a href="mailto:scott@pointyhat.ca" target="_blank">scott@pointyhat.ca</a>> wrote:<br>
> I have the following macro:<br>
><br>
> (define-syntax (define/test stx)<br>
> (syntax-parse stx<br>
> [(_ (id arg ...) body ... #:test test-body ...)<br>
> (with-syntax ([id-str (symbol->string (syntax->datum #'id))])<br>
> #'(begin<br>
> (define (id arg ...) body ...)<br>
> (print id-str)<br>
> (module+ test<br>
> (require rackunit)<br>
> (test-case id-str<br>
> test-body ...))))]))<br>
><br>
> Which handles some testing boilerplate and allows me to use it like so:<br>
><br>
> (define/test (my-fn a b c)<br>
> (print a)<br>
> (print b)<br>
> (print c)<br>
> #:test<br>
> (check-true #t)<br>
> (check-false #t))<br>
><br>
> The problem is that the (require rackunit) expression inside of (module+<br>
> test) is not being picked up after macro expansion. Running either the code<br>
> or the tests (via raco test) results in: unbound identifier check-true.<br>
><br>
> Adding (module+ (require rackunit)) to the top of the file solves the<br>
> problem and both the file and tests run as expected.<br>
><br>
> What am I missing?<br>
><br>
> Thanks.<br>
> --<br>
> Talk to you soon,<br>
><br>
> Scott Klarenbach<br>
><br>
> PointyHat Software Corp.<br>
> <a href="http://www.pointyhat.ca" target="_blank">www.pointyhat.ca</a><br>
> p <a href="tel:604-568-4280" value="+16045684280" target="_blank">604-568-4280</a><br>
> e <a href="mailto:scott@pointyhat.ca" target="_blank">scott@pointyhat.ca</a><br>
> 200-1575 W. Georgia<br>
> Vancouver, BC V6G2V3<br>
><br>
> _______________________________________<br>
> To iterate is human; to recur, divine<br>
><br>
> ____________________<br>
> Racket Users list:<br>
> <a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
><br>
<br>
____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
</blockquote></div>
</div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br>Talk to you soon,<br><br>Scott Klarenbach<br><br>PointyHat Software Corp.<br><a href="http://www.pointyhat.ca" target="_blank">www.pointyhat.ca</a><br>
p <a href="tel:604-568-4280" value="+16045684280" target="_blank">604-568-4280</a><br>e <a href="mailto:scott@pointyhat.ca" target="_blank">scott@pointyhat.ca</a><br><span style="color:rgb(34,34,34);font-size:13px;font-family:arial,sans-serif">200-1575 W. Georgia</span><br>
Vancouver, BC <span style="color:rgb(34,34,34);font-size:13px;font-family:arial,sans-serif">V6G2V3</span><br><br>_______________________________________<br>To iterate is human; to recur, divine
</div></div><div><div>
</div></div></blockquote></div></div></div><br></div></div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Talk to you soon,<br><br>Scott Klarenbach<br><br>PointyHat Software Corp.<br><a href="http://www.pointyhat.ca" target="_blank">www.pointyhat.ca</a><br>p 604-568-4280<br>
e <a href="mailto:scott@pointyhat.ca" target="_blank">scott@pointyhat.ca</a><br><span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">200-1575 W. Georgia</span><br>
Vancouver, BC <span style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">V6G2V3</span><br><br>_______________________________________<br>To iterate is human; to recur, divine
</div>