Read Eli's answer first. Then, based on Eli's answer, can you implement a defined? macro defined? in the following way:
#lang racket ; The macro (define-syntax (defined? stx) (syntax-case stx () [(_ id) (with-syntax ([v (identifier-binding #'id)]) #''v)])) ; Tests (define x 3) (if (defined? x) 'defined 'not-defined) ; -> defined (let ([y 4]) (if (defined? y) 'defined 'not-defined)) ; -> defined (if (defined? z) 'defined 'not-defined) ; -> not-defined
It works for this main case, but it has a problem: if z is undefined, the if branch, which believes that it is defined and uses its value, will cause a compile-time error, because normal if checks its condition value at runtime (dynamically ):
; This doesn't work because z in `(list z)' is undefined: (if (defined? z) (list z) 'not-defined)
So what you probably want is an if-defined macro that tells you at compile time (and not at run time) which if branch to take:
#lang racket ; The macro (define-syntax (if-defined stx) (syntax-case stx () [(_ id iftrue iffalse) (let ([where (identifier-binding #'id)]) (if where #'iftrue #'iffalse))])) ; Tests (if-defined z (list z) 'not-defined) ; -> not-defined (if-defined t (void) (define t 5)) t ; -> 5 (define x 3) (if-defined x (void) (define x 6)) x ; -> 3
source share