How to convert r6rs macro involving syntax-case to racket?

120 Views Asked by At

I am learning scheme/racket macros, and trying to make the following macro from sweet-macros work under racket 8.6.

#lang racket

(require (for-meta 1 srfi/1)) ; for cons* and fold-right
(provide guarded-syntax-case)

;;GUARDED-SYNTAX-CASE
(define-syntax guarded-syntax-case
  (let ((add-clause
         (lambda (clause acc)
           (syntax-case clause ()
             ((pattern skeleton . rest)
                (syntax-case #'rest ()
                  ((cond? else1 else2 ...)
                   (cons*
                    #'(pattern cond? skeleton)
                    #'(pattern (begin else1 else2 ...))
                    acc))
                  ((cond?)
                   (cons #'(pattern cond? skeleton) acc))
                  (()
                   (cons #'(pattern skeleton) acc))
                  ))))))
    (lambda (x)
      (syntax-case x ()
        ((guarded-syntax-case y (literal ...) clause ...)
         (with-syntax (((c ...) (fold-right add-clause '() #'(clause ...))))
           #'(syntax-case y (literal ...) c ...)))))))
;;END

The macro was written for plt-r6rs, but I wanted to experiment with it in the racket interpreter/REPL (, which is forbidden in racket's r6rs).

I couldn't make much progress except for adding the imports:

(require (for-meta 1 srfi/1))

Now when testing guarded-syntax-case, I assumed that it is similar to racket/r6rs syntax-case but with some added functionality. So I tested the following adapted example:

(syntax->datum
   (guarded-syntax-case #'(+ 1 2) ()
    [(op n1 n2) #'(- n1 n2)]))

but got an error:

. . null-list?: argument out of domain #<syntax:my-sweet.rkt:26:61 (((op n1 n2) (syntax (- n1 n2))))>

I couldn't figure out how to fix the error after a long time, since I am just beginning to learn macros.

Could some one please help explain why the macro doesn't work with racket, and how to make it work with racket?

I can only guess that the branch:

              (()
               (cons #'(pattern skeleton) acc))

is reached in the above example. I read that different scheme implementations can handle #'(pattern skeleton) differently during conversion to/from syntax objects. So the cons here could be a problem.

1

There are 1 best solutions below

0
On

(not an answer to the question but too long for comment):

One may observe that guarded-syntax-case seems to be emulating the standard R6RS fender option of syntax-case, which is available in Racket. The multi-define example of using guarded-syntax-case in sweet-macros can be written:

#lang racket
(require test-engine/racket-tests)
        
(define-syntax multi-define
  (lambda (x)
    (syntax-case x ()
      [(_ (name ...) (value ...))                       ; pattern
       (or (= (length (syntax->datum #'(name ...)))     ; fender ("guard")
              (length (syntax->datum #'(value ...))))   ;
         (raise-syntax-error 'multi-define "Names and values do not match" #f #f
                             (list #'(name ...) #'(value ...))))
       #'(begin (define name value) ...) ])))           ; template ("skeleton")

(multi-define (a b) (1 2))
(check-expect a 1)
(check-expect b 2)

(multi-define (a b c) (1 2))

(test)