简体   繁体   中英

unbound variable in racket macro

I am testing a wrapper macro around the racket syntax-case macro. At step 1, it does nothing interesting and simply passes through all the parts to syntax-case directly as follows:

#lang racket

;; definition
(define-syntax guarded-syntax-case
  (lambda (x)
      (syntax-case x ()
        ((guarded-syntax-case y (literal ...) clause ...)
         #'(syntax-case y (literal ...) clause ...)
         ))))

;; test case
(define-syntax (binop stx)
  (guarded-syntax-case stx () ; *problem site*
        [(_ op n1 n2) #'(op n1 n2)]))

But this simple case fails with the following error at the empty brackets () labeled with problem site labeled in above code:

; ....rkt:11:27: #%app: missing procedure expression;
;  probably originally (), which is an illegal empty application
;   after encountering unbound identifier (which is possibly the real problem):
;    guarded-syntax-case
;   in: (#%app)

I couldn't figure out what could be wrong in this simple pass-through macro. The error message seems to suggest that there is a unbound variable somewhere, which I couldn't identify. I would think that the literal... should be matched to empty.

Could someone help explain what went wrong and how to fix the macro?

The problem is that guarded-syntax-case is not recognized as a macro in the correct phase . In particular, when you (define-syntax guarded-syntax-case...) in your program, you define the macro guarded-syntax-case that is available in phase 0. But forms in (define-syntax (binop stx)...) must be in phase 1.

There are two ways to correct the mistake.

  1. You can wrap (define-syntax guarded-syntax-case...) inside begin-for-syntax . However, doing so would require syntax-case and other stuff to be available in phase 2. So you need an additional (require (for-meta 2 racket/base)) . Here's the full code:
#lang racket

(require (for-meta 2 racket/base))

;; definition
(begin-for-syntax
  (define-syntax guarded-syntax-case
    (lambda (x)
      (syntax-case x ()
        ((guarded-syntax-case y (literal ...) clause ...)
         #'(syntax-case y (literal ...) clause ...))))))

;; test case
(define-syntax (binop stx)
  (guarded-syntax-case stx () ; *problem site*
                       [(_ op n1 n2) #'(op n1 n2)]))

(binop + 1 2) ;=> 3
  1. Alternatively, you can define a (sub)module that provides guarded-syntax-case , and then require the (sub)module with for-syntax . Here's the full code:
#lang racket

(module lib racket
  (provide guarded-syntax-case)
  ;; definition
  (define-syntax guarded-syntax-case
    (lambda (x)
      (syntax-case x ()
        ((guarded-syntax-case y (literal ...) clause ...)
         #'(syntax-case y (literal ...) clause ...))))))

(require (for-syntax 'lib))

;; test case
(define-syntax (binop stx)
  (guarded-syntax-case stx () ; *problem site*
                       [(_ op n1 n2) #'(op n1 n2)]))

(binop + 1 2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM