Would that affect the loading of rackunit during main vs test runs of the file? For example, >> racket file-that-uses-macro.rkt >> raco test file-that-uses-macro.rkt
;; will the *non-test *invocation now require rackunit due to the macro definition, where as the dual require inside of module+ would not? Thanks. On Wed, Jan 8, 2014 at 4:29 PM, Carl Eastlund <carl.eastl...@gmail.com>wrote: > That's a good solution. I can suggest one that saves you having to add > two requires each time you use the macro, although it's a small > optimization: simply add (require rackunit) to the top of the file where > you define the macro, entirely outside the macro definition. Then you > don't need the extra (require rackunit) inside the macro template; you'll > be able to refer to test-case from rackunit the same way you referred to > require and provide from racket. > > Carl Eastlund > > > On Wed, Jan 8, 2014 at 7:13 PM, Scott Klarenbach <sc...@pointyhat.ca>wrote: > >> Sorry, gmail sent before I could paste :( >> >> ... >> >> So I changed the macro definition to: >> >> (define-syntax (define/spec stx) >> (syntax-parse stx >> [(_ (proc:id arg:expr ...) >> body:expr ... >> #:doc contract:expr arg-spec:expr desc:expr >> #:test test-body:expr ...) >> (with-syntax ([id-str (symbol->string (syntax->datum #'proc))] >> [ru-require (format-id stx "~a" "rackunit")]) >> #'(begin >> (provide >> (proc-doc/names proc contract arg-spec desc)) >> (define (proc arg ...) body ...) >> (module+ test >> (require ru-require) >> (require rackunit) >> (test-case id-str test-body ...))))])) >> >> Notice the extra (require rackunit), after the modified (require >> ru-require). Is that the right solution? >> >> >> On Wed, Jan 8, 2014 at 4:00 PM, Carl Eastlund <carl.eastl...@gmail.com>wrote: >> >>> On Wed, Jan 8, 2014 at 6:44 PM, Scott Klarenbach <sc...@pointyhat.ca>wrote: >>> >>>> Thanks guys. >>>> >>>> I changed it to this: >>>> >>>> (define-syntax (define/test stx) >>>> (syntax-parse stx >>>> [(_ (proc:id arg:expr ...) >>>> body:expr ... >>>> #:test test-body:expr ...) >>>> (with-syntax ([id-str (symbol->string (syntax->datum #'proc))] >>>> [ru-require (format-id stx "~a" "rackunit")]) >>>> #'(begin >>>> (define (proc arg ...) body ...) >>>> (module+ test >>>> (require ru-require) >>>> (test-case id-str test-body ...))))])) >>>> >>>> and it works now. Is that what you meant Carl? >>>> >>> >>> Yep, that's it. >>> >>> >>>> The problem is that check-true (and check-false) are not in scope (as >>>>> you discovered) during expansion. >>>> >>>> >>>> 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. >>>> >>> >>> 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. >>> >>> 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.) >>> >>> 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. >>> >>> 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?". >>> >>> 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. >>> >>> Good luck! >>> >>> >>>> On Wed, Jan 8, 2014 at 2:37 PM, Carl Eastlund <carl.eastl...@gmail.com >>>> > wrote: >>>> >>>>> 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. >>>>> On Jan 8, 2014 5:29 PM, "Stephen Chang" <stch...@ccs.neu.edu> wrote: >>>>> >>>>>> The problem is that check-true (and check-false) are not in scope (as >>>>>> you discovered) during expansion. Here is one way to fix your problem >>>>>> by recapturing the test expressions to have the proper context. You >>>>>> can also use syntax-local-introduce instead of the lambda (someone >>>>>> correct me if this is not proper usage). >>>>>> >>>>>> #lang racket >>>>>> (require (for-syntax syntax/parse)) >>>>>> >>>>>> (define-syntax (define/test stx) >>>>>> (syntax-parse stx >>>>>> [(_ (id arg ...) body ... #:test test-body ...) >>>>>> (with-syntax ([id-str (symbol->string (syntax->datum #'id))] >>>>>> [(new-test-body ...) >>>>>> (map >>>>>> (λ (s) (datum->syntax #'here (syntax->datum s))) >>>>>> (syntax->list #'(test-body ...)))]) >>>>>> #'(begin >>>>>> (define (id arg ...) body ...) >>>>>> (print id-str) >>>>>> (module+ test >>>>>> (require rackunit) >>>>>> (test-case id-str >>>>>> new-test-body ...))))])) >>>>>> >>>>>> (define/test (my-fn a b c) >>>>>> (print a) >>>>>> (print b) >>>>>> (print c) >>>>>> #:test >>>>>> (check-true #t) >>>>>> (check-false #t)) >>>>>> >>>>>> On Wed, Jan 8, 2014 at 4:53 PM, Scott Klarenbach <sc...@pointyhat.ca> >>>>>> wrote: >>>>>> > I have the following macro: >>>>>> > >>>>>> > (define-syntax (define/test stx) >>>>>> > (syntax-parse stx >>>>>> > [(_ (id arg ...) body ... #:test test-body ...) >>>>>> > (with-syntax ([id-str (symbol->string (syntax->datum #'id))]) >>>>>> > #'(begin >>>>>> > (define (id arg ...) body ...) >>>>>> > (print id-str) >>>>>> > (module+ test >>>>>> > (require rackunit) >>>>>> > (test-case id-str >>>>>> > test-body ...))))])) >>>>>> > >>>>>> > Which handles some testing boilerplate and allows me to use it like >>>>>> so: >>>>>> > >>>>>> > (define/test (my-fn a b c) >>>>>> > (print a) >>>>>> > (print b) >>>>>> > (print c) >>>>>> > #:test >>>>>> > (check-true #t) >>>>>> > (check-false #t)) >>>>>> > >>>>>> > The problem is that the (require rackunit) expression inside of >>>>>> (module+ >>>>>> > test) is not being picked up after macro expansion. Running either >>>>>> the code >>>>>> > or the tests (via raco test) results in: unbound identifier >>>>>> check-true. >>>>>> > >>>>>> > Adding (module+ (require rackunit)) to the top of the file solves >>>>>> the >>>>>> > problem and both the file and tests run as expected. >>>>>> > >>>>>> > What am I missing? >>>>>> > >>>>>> > Thanks. >>>>>> > -- >>>>>> > Talk to you soon, >>>>>> > >>>>>> > Scott Klarenbach >>>>>> > >>>>>> > PointyHat Software Corp. >>>>>> > www.pointyhat.ca >>>>>> > p 604-568-4280 >>>>>> > e sc...@pointyhat.ca >>>>>> > 200-1575 W. Georgia >>>>>> > Vancouver, BC V6G2V3 >>>>>> > >>>>>> > _______________________________________ >>>>>> > To iterate is human; to recur, divine >>>>>> > >>>>>> > ____________________ >>>>>> > Racket Users list: >>>>>> > http://lists.racket-lang.org/users >>>>>> > >>>>>> >>>>>> ____________________ >>>>>> Racket Users list: >>>>>> http://lists.racket-lang.org/users >>>>>> >>>>> >>>> >>>> >>>> -- >>>> Talk to you soon, >>>> >>>> Scott Klarenbach >>>> >>>> PointyHat Software Corp. >>>> www.pointyhat.ca >>>> p 604-568-4280 >>>> e sc...@pointyhat.ca >>>> 200-1575 W. Georgia >>>> Vancouver, BC V6G2V3 >>>> >>>> _______________________________________ >>>> To iterate is human; to recur, divine >>>> >>> >>> >> >> >> -- >> Talk to you soon, >> >> Scott Klarenbach >> >> PointyHat Software Corp. >> www.pointyhat.ca >> p 604-568-4280 >> e sc...@pointyhat.ca >> 200-1575 W. Georgia >> Vancouver, BC V6G2V3 >> >> _______________________________________ >> To iterate is human; to recur, divine >> > > -- Talk to you soon, Scott Klarenbach PointyHat Software Corp. www.pointyhat.ca p 604-568-4280 e sc...@pointyhat.ca 200-1575 W. Georgia Vancouver, BC V6G2V3 _______________________________________ To iterate is human; to recur, divine
____________________ Racket Users list: http://lists.racket-lang.org/users