In macro, is object a macro or a procedure?

Hi all,

In the following example, a syntax error is raised because of (apply op args) can't work when op is a macro like and.
How can I force the macro to go through the second branch when apply doesn't apply?

#lang racket
(require (for-syntax racket/base
                     syntax/parse))

(define-syntax (thingy stx)
  (syntax-parse stx
    [(_ (op:expr arg:expr ...))
     #'(let ([vals (list arg ...)])
         (list (apply op vals)  ; can't apply `and` here
               (map cons (list 'arg ...) vals)))
     ]
    [(_ ex:expr)
     #'ex]))


(thingy (+ 3 4)) ; fine
(thingy (and #true #false)) ; fails with `and: bad syntax`

It’s possible to create something like my-and which is still a macro, but can be used as an identifier macro (and therefore would work with apply). I guess you want stuff like my-and to go through the first branch?

Here’s one possible implementation.

#lang racket

(require syntax/parse/define)

(define-syntax-parser my-and
  [(_ x ...) #'(and x ...)]
  [_:id #'(λ args (andmap values args))])

'my-and-works
(my-and #f #t)
(map my-and '(#t #t #f #f) '(#t #f #t #f))

(define-for-syntax (id-use? t)
  (define proc (syntax-local-value t (λ () #f)))
  (cond
    [proc
     (with-handlers ([exn:fail? (λ (_) #f)])
       (proc t)
       #t)]
    [else #t]))

(define-syntax (thingy stx)
  (syntax-parse stx
    [(_ (op:expr arg:expr ...))
     #:when (id-use? #'op)
     #'(let ([vals (list arg ...)])
         (list (apply op vals)
               (map cons (list 'arg ...) vals)))
     ]
    [(_ ex:expr)
     #'ex]))

'thingy-works
(thingy (+ 3 4)) ; fine
(thingy (and #true #false))
(thingy (my-and #true #false))


#lang racket
(require (for-syntax racket/base
syntax/parse))

(define-syntax (thingy stx)
(syntax-parse stx
[(_ (op:expr arg:expr ...))
#:with (val ...) (generate-temporaries #'(arg ...))
#'(let ([val arg] ...)
(list (op val ...) ; can't apply `and` here
(map cons (list 'arg ...) (list val ...))))
]
[(_ ex:expr)
#'ex]))

(thingy (+ 3 4)) ; fine
(thingy (and #true #false)) ; fails with `and: bad syntax`

Thanks Sorawee!

I'm not sure I want something like my-and actually, because some branches of the and may not be meant to be evaluated.

However, something like id-use? is what I'm looking for. Though I'm hoping to not have to use with-handlers if possible.

Thanks Matthias!

Unfortunately, I don't think I'm allowed to evaluate the arguments of the and beforehand, because it defies the evaluation order that and creates.

For example, (thingy (or (not (vector? v)) (vector-ref v 0))) will fail if v is not a vector, but shouldn't.

So I think I need to make the macro fall back to the second branch instead.

The evaluation order of my revision is the same as yours (if yours worked).

Absolutely, but mine doesn't work either! :smiley:

That's why I want to push cases where I can't apply to the second branch —
but I guess the "Can I use apply?" is a proxy for "is it safe to evaluate the inner expressions before the outer one?".

Your revision helped me realize this more clearly.