Flatten syntax tree using hygenic macros

Viewed 72

Is it possible to write an R5RS macro that would "flatten" arbitrarily deep syntax tree?
Example:

(flatten-syntax (a (b (c d)) e)) => (a b c d e)

My endgoal is to have another macro that would work like this:

(declare-tree (a (b (c d)) e))
 => 
(begin (define a #f) (define b #f) (define c #f) (define d #f) (define e #f))

but it should be easy to define if flatten-syntax is available.

The most challenging part for me here is the syntax-rules-only restriction, but if you have syntax-case solution, please also post it.

My progress on this problem stalled at this point:

(define-syntax flatten-syntax-helper
  (syntax-rules ()
    ((_ buf (x . xs))
     (flatten-syntax-helper
      (flatten-syntax-helper buf x) xs))
    ((_ buf ())
     buf)
    ((_ buf x)
     (x . buf))))
(define-syntax-rule (my-flatten-syntax T)
  (flatten-syntax-helper () T))

In guile, ,expand (my-flatten-syntax (a (b (c d)) e)) results in syntax error "failed to match any pattern in form my-flatten-syntax".

1 Answers

Here's my quick attempt:

#lang racket

(define-syntax reverse-macro
  (syntax-rules ()
    [(_ () (result ...)) '(result ...)]
    [(_ (x xs ...) (result ...)) (reverse-macro (xs ...) (x result ...))]))

(define-syntax flatten-syntax-aux
  (syntax-rules ()
    [(_ ((xs ...) ys ...) (result ...))
     (flatten-syntax-aux (xs ... ys ...) (result ...))]
    [(_ (x xs ...) (result ...))
     (flatten-syntax-aux (xs ...) (x result ...))]
    [(_ () (result ...))
     (reverse-macro (result ...) ())]))

(define-syntax-rule (flatten-syntax xs)
  (flatten-syntax-aux xs ()))

(flatten-syntax (a (b (c d)) e)) ;=> '(a b c d e)

Indeed, you can create declare-tree by adjusting flatten-syntax a little bit, but it might be surprising to you that defining declare-tree directly is in fact much easier:

#lang racket

(define-syntax declare-tree
  (syntax-rules ()
    [(_ ((xs ...) ys ...))
     (begin (declare-tree (xs ...))
            (declare-tree (ys ...)))]
    [(_ (x xs ...))
     (begin (define x #f)
            (declare-tree (xs ...)))]
    [(_ ())
     (begin)]))

(declare-tree (a (b (c d)) e))
(list a b c d e) ;=> '(#f #f #f #f #f)

This is because declare-tree actually doesn't need to flatten the structure. It can generate nested begin, like:

(begin
  (begin (define a #f)
         (define b #f))
  (begin (define c #f)
         (define d #f)))
Related