note: This was also posted to the comp.lang.scheme earlier today. I normally wouldn't cross-post, but after I noticed the extremely low traffic on the newsgroup, I decided to try a more active, if less specialized, forum.

As part of a larger project, I am writing a macro that defines a variable and binds it to a list of pairs, where most of the pairs map a pattern and a value. Each pattern is a list, which may have a combination of symbols and strings.

I am something of a novice with (define-syntax), and have struggled to get this to where I want it to go; while I have learned a fair amount in the process, I apparently don't have a clear enough understanding yet. The current version of the macro, which I've based partly on macro designs from The Scheme Programming Language, 3rd ed. and other sources, is built of three sub-procedures: a fender predicate, a syntax-case which recognizes the individual pattern/value pairs, and the main syntax-case for the overall macro. Given that it is not that complicated a set of patterns it recognizes, I am fairly certain it could be a lot simpler, but this is the best I have managed so far. The code is for R6RS, and I am testing it in Ypsilon 0.9.6-update3.

 (define-syntax define-field-pattern
   (lambda (x)
     (let*
         ((value-fender?
           (lambda (w v)
             (and (integer? v)
                  (> (expt 2 w) v))))
          (expand-pattern
           (lambda (width elements)
             (syntax-case elements (default =>)
               ((default => ?value)
                (value-fender? width (syntax ?value)) ;value valid?                
                (cons 'default (syntax ?value)))
               ((?el => ?value)
                (value-fender? width (syntax ?value)) ;value valid?
                (cons (list (syntax ?el) (syntax ?value))))
               ((?el-0 ?el-1 ... => ?value)
                (value-fender? width (syntax ?value)) ;value valid?
                (let ((element (syntax ?el-0))
                      (rest (syntax (?el-1 ...)))
                      (value (syntax ?value)))
                  (list
                   (cons
                    (let iter ((curr-element element)
                               (next-element (car rest)))
                      (append (list curr-element)
                              (if (null? next-element)
                                  '()
                                  (iter (next-element (cdr rest))))))
                    value))))))))
       (syntax-case x (width)
         ((_ ?name (width ?size) (?pattern-0 ?pattern-1 ...))
          (syntax
           (define ?name
             (append (list (cons 'width ?size))
                     (let loop ((pattern ?pattern-0)
                                (later-patterns (?pattern-1 ...)))
                       (expand-pattern (syntax ?size) pattern)
                       (if (null? later-patterns)
                           '()
                           (loop (car later-patterns) (cdr later-patterns))))))))))))

The test case I am using should expand to '((width . 3) ((bar) . 2)), where width is the bit-width of the field it represents and (bar) is the stored pattern. However, I cannot figure out how to get the defined list to be quoted without quoting the actual code. I expect the answer lies with some combination of quasiquoting and unquoting, but I am unclear on how to get the correct sequence.

Any advice would be appreciated.

Recommended Answers

All 4 Replies

I'm more of a Racket programmer, and I don't usually use macros. I'll try to help though. Is this R5RS?

Edit: Nevermind. R6RS.

It does look line your default case should be quoting everything. What was the input for the expected output? What was the actual output?

The test code is:

(define-field-pattern foo (width 3)
  ((bar => 2)))

(display foo)
(newline)

This should have printed the line shown above; the actual result was the following error message:

error: attempt to reference unbound identifier bar
  >  (bar => 2)

This seems to imply that it isn't recognizing the pattern at all, but I may be misinterpreting it. Oh, if I add a (syntax) clause after ?name, it does run, but it gives the following:

(#<syntax append> (#<syntax list> (#<syntax cons> (#<syntax quote>
#<syntax width>) 3)) (#<syntax let> #<syntax loop> ((#<syntax pattern>
(#<syntax bar> #<syntax =>> 2)) (#<syntax later-patterns> ()))
(#<syntax expand-pattern> (#<syntax syntax> 3) #<syntax pattern>)
(#<syntax if> (#<syntax null?> #<syntax later-patterns>) (#<syntax
quote> ()) (#<syntax loop> (#<syntax car> #<syntax later-patterns>)
(#<syntax cdr> #<syntax later-patterns>)))))

Which clearly isn't what I am looking for.

With the help of godek at comp.lanf.scheme (which wasn't so dead as it seemed), I was able to get a working and vastly simpler macro written. For the record, the final version is:

 (define-syntax define-field-pattern
  (lambda (x)
    (syntax-case x (width default =>)
      ((_ name (width w) ((p-0 ... => value) ... (default => value-n)))
       #'(define name `((width . w) (((p-0 ...) . value) ...
                     (default . value-n)))))
      ((_ name (width w) ((p-0 ... => value) ...))
       #'(define name `((width . w) (((p-0 ...) . value) ...))))
      )))

Thanks for everyone who tried working on this for me.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.