[racket] variables within macros

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Sun Jan 20 17:26:33 EST 2013

On Jan 20, 2013, at 6:35 AM, Tim Brown wrote:

> Below, you use define-syntax-rule.

Your example didn't seem to call for more. 
And define-syntax-rule is just a syntactic
extension :-) for defining simplistic syntax 
extensions. Syntax objects are all under the 
hood. 

But you are correct. When I create extensions 
for others I use syntax-case or syntax-parse. 
With those I can check more properties (easily), 
I can process the syntax a bit differently, and 
I can signal errors with good messages (mostly 
automatically). See end of message. But #' is 
all I need. 

If I can, I still start with syntax-rule(s) to get
a simple prototype going. All I have is 26 years
of experience writing hygienic syntax extension, 
so I proceed step by step. 


>>> On Jan 18, 2013, at 12:36 PM, Tim Brown wrote:
>>>> A concrete example is that I am trying to write a #lang language.
>>> 
>>> Honestly, I would never ever try to write a #lang first.
>>> That's more than most people want.
> 
> This "project" was prompted by plt-games.com,

(What is that? Link doesn't work.) 

> and I am grateful that you
> too not only the time, but "On 01/19/2013 06:31 PM" this kind of time to
> answer me.

(we like what we do) 


> 
>>> GOAL: Let's say we wish to be able to write
>>> ...
>>> because we believe in self-documentation of functions via tests.
>>> Viva la design recipe.
> 
> Are you applauding my desire to build tests into my definitions (in
> which case, thanks - but it's not my idea)?

(This was a silly reference to HtDP and I should not have made it.
I distracted. Yes, I like your define/test construct because it plays 
nicely with the design recipe from htdp.) 




> I have to ask... define/test is a syntax-rule. It has always confused
> me slightly that (after hearing about a syntax phase and runtime phase)
> I can use define/test after a simple "require" of the library. The
> syntax rule isn't even provided from the library as "something special".
> I *think* I can see how this is consistent, but is there a one-line
> statement you can make that helps make this clear?



This is a cool thing. Yes, define/test is provided as a 'syntax thing'. 
The compiler knows how to retrieve those syntax things when it sees a
(require foo) specification. It does so. It uses them for the compilation
of the module. And it then links against the 'run-time things' that are 
exported from the module. 

(If modules were first class values -- say like numbers or functions ---
you would not be able to do this easily.) 


[[ More on syntax testing in a separate thread. ]] 



>>> IF I found such a software engineering reason, I would try to
>>> figure out how to solve it w/o resorting to a new language.
> 
> I think there needs to be a certain distinguish made between software
> engineering and computer science / PL investigation. I do the former
> for a living and, with that hat on, I agree with you 100%ly that we
> should avoid new languages (in this sense).
> 
> However, the computer scientist in me takes great joy at contemplating
> esolangs, and what they can teach us. I'll restate that one of the
> things that (I think that) Racket promises is a PL playground, and I
> want to know that, if the urge takes me, I have the means (the tools
> and the skills) to implement 4DL(*).


Agreed. But from teaching for 26 years I have learned that no matter 
where you are a novice you get faster to your goal when you learn to 
break up the gap into several steps. 

That's the essence of the design recipe. I preach it in my freshman
courses. All hotshot freshman who "know how to program" ... and "better
than this teacher" ... try to skip it. But then, around week 5 we get 
to this point where the not-so-hotshot kids can solve the problems and
the hot-red-shots are red in their face -- because they can't. I then 
explain that taking small steps may seem like a detour and it sometimes
is a detour but you need to learn to judge when it really is. And until
you know the design recipe inside-out, you can't make this judgment. 

Since almost everything "learning" is like designing programs, apply 
the design recipe. Feel the force. 

-- Matthias

#lang racket

(require rackunit)

(provide 
 (all-from-out rackunit)
 ;; ------------------------------------------
 ;; syntax: define/test
 ;; (define/test (f x ...) (tests (lhs == rhs) ...) e ...)
 ;; expands to a combination of two items:
 ;; -- the function (define (f x ...) e ...) 
 ;; -- tests (check-equals? lhs rhs) ... in submodule test 
 define/test
 ;; beauty keywords
 tests
 ==)

;; -----------------------------------------------------------------------------

(require rackunit (for-syntax syntax/parse))

(define-syntax (tests stx)
  (raise-syntax-error #f "used out of context"))

(define-syntax (== stx)
  (raise-syntax-error #f "used out of context"))

(define-syntax (define/test stx)
  (syntax-parse stx #:literals (tests ==)
    [(define/test (f:id x:id ...) 
       (tests (lhs == rhs) ...)
       e:expr ...)
     #'(begin
         (module+ test
           (check-equal? lhs rhs)
           ...)
         (define (f x ...)
           e ...))]))




Posted on the users mailing list.