[racket] Lesson from the macro exercise

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Tue Oct 12 11:54:33 EDT 2010

Syntax/parse looks great!

I haven't played with it before, but it I like the approach.
Two questions:

   1. What does the error
          pattern: attribute has wrong depth (expected 0, found 1) in: d
      mean?  The program belows gives this error.
   2. Why is datum not a pre-defined syntax-class?

/Jens Axel

#lang racket
(require (for-syntax syntax/parse))

;;    <cas-cad-e>   ::= (cas-cad-e <val-expr> <case-clause> ...+)
;;    <case-clause> ::= [(<datum> ...) <then-expr> ...+]

(define-syntax-parameter break
  (λ (stx) (raise-syntax-error 'break "The keywork break was used of
context." stx)))

(define-syntax (casc stx)
  (define-syntax-class datum
    #:attributes (d)
    (pattern d:expr))
  (define-syntax-class case-clause
    #:attributes (d te)
    (pattern [(d:datum ...) te:expr ...+]))
  (syntax-parse stx
    [(_ value-expr:expr clause:case-clause ... last-clause:case-clause)
     (with-syntax ([(label ...)      (generate-temporaries #'(clause ...))]
                   [last-label       (generate-temporary)]
                   [(next ...)       (stx-cdr #'(label ... last-label))])
       #'(let/ec break1
             (syntax-parameterize ([break (make-rename-transformer #'break1)])
              (letrec ([label      (λ () clause.te ... (next))]
                       [last-label (λ () last-clause.te ...)])
                (case ve
                  [(clause.d ...)      (label)]
                  [(last-clause.d ...) (last-label)]
                  [else (void)])))))]))

2010/10/12 Robby Findler <robby at eecs.northwestern.edu>:
> syntax/parse!  :)
> Robby
> On Tue, Oct 12, 2010 at 3:46 AM, Jens Axel Søgaard
> <jensaxel at soegaard.net> wrote:
>> There have now been several solutions to the macro exercise.
>> Is there a systematic approach of deriving a solution?
>> Here are some steps that could be included in a macro writing recipe.
>> 1.  Write some examples with their expected results.
>>     Remember corner cases
>>     (Get to know the semantics. Are all cases made explicit?)
>> 2.  Write some examples of errorneous usage of the macro.
>>     (Get to know the syntax. Write down a BNF if it is missing.)
>>     Write down the corresponding error messages. Word them
>>     in terms of the macro construct.
>> 3.  Manually write your examples in code without using
>>     the construct you are about to define. If a construct
>>     with a similar behavior already exists, use it.
>> 4.  Look for a pattern to determine how the macro expands.
>>     (It helps to name the various subexpressions.)
>> 5.  Implement the macro
>>     5a. Use syntax-case and with-syntax to give names to
>>          parts of your input.
>>     5b. Use generate-temporaries to generate new names.
>>     5c. Use define-syntax-parameter and syntax-parameterize if your
>>          macro uses a new keyword.
>>     5d. Use raise-syntax-error to signal syntax errors.
>>          Use the 3rd argument of raise-syntax-error to make the error
>> location precise.
>>     5e. Use define-for-syntax to define helper functions.
>> 6. Test your macro.
>>    Use all examples from 1.
>>    Test the case where your macro is used in the output of another macro.
>> Note: syntax-rules macros are not the best choice for informative
>> error messages.
>> --
>> Jens Axel Søgaard
>> _________________________________________________
>>  For list-related administrative tasks:
>>  http://lists.racket-lang.org/listinfo/users

Jens Axel Søgaard

Posted on the users mailing list.