[racket] variables within macros
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 ...))]))