# In macro, is object a macro or a procedure?

**URL:** <https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323>\
**Category:** Questions & Answers\
**Tags:** question, macro\
**Created:** [November 15, 2024, 12:44pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323 "2024-11-15T12:44:52Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 15, 2024, 12:44pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/1 "2024-11-15T12:44:52Z")

</div>

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?

```scheme
#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`

```

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [November 15, 2024, 1:23pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/2 "2024-11-15T13:23:35Z")

</div>

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.

```scheme
#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))

```

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [November 15, 2024, 1:30pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/3 "2024-11-15T13:30:11Z")

</div>

```scheme

#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`

```

---

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 15, 2024, 1:36pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/4 "2024-11-15T13:36:53Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 15, 2024, 1:41pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/5 "2024-11-15T13:41:00Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)\
**Post date:** [November 15, 2024, 2:07pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/6 "2024-11-15T14:07:28Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 15, 2024, 2:12pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/7 "2024-11-15T14:12:02Z")

</div>

Absolutely, but mine doesn't work either! 😃

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.

---

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 22, 2024, 11:13am UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/8 "2024-11-22T11:13:10Z")

</div>

I still think we should be able to do better than `syntax-local-value` here.

In particular, when writing `(= and 3)`, DrRacket complains with a syntax error `and: bad syntax in: and`, which means that it is possible to determine that `and` cannot be in non-application position at compile time, supposedly without evaluating it.

But I don't know how to 'catch' this in a macro.

---

<div class="post-metadata">

**Author:** ![bakgatviooldoos](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/bakgatviooldoos/32/1381_2.png) [@bakgatviooldoos](https://racket.discourse.group/u/bakgatviooldoos)\
**Post date:** [November 22, 2024, 11:48am UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/9 "2024-11-22T11:48:14Z")

</div>

So, what I think `and` is doing here, is determining that the arguments passed to it is not a syntax-list (it is bare?):

```scheme
;; from qq-and-or.rkt
(define-syntaxes (and)
  (let-values ([(here) (quote-syntax here)])
    (lambda (x)
      (if (not (stx-list? x))
          (raise-syntax-error #f "bad syntax" x)
          (void))
      ...)
    ...))

```

I guess you might be able to use that to check whether something is a macro or not? But I am speaking in ignorance.

* * *

Edit: So iets?

```scheme
#lang racket

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

(begin-for-syntax
  (define (check stx)
    (with-handlers ([exn:fail? (λ _ #false)])
      (values (syntax-local-eval stx)))))

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

    [(_ ex:expr)
     #'ex]))

(thingy (+ 3 4)) ; fine
(thingy (and #true #false)) ; good to go?
;=>
; '(7 ((3 . 3) (4 . 4)))
; #f

```

* * *

Edit: I should have paid more attention to @sorawee's answer, since he did basically the same thing. TIL.

---

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 22, 2024, 12:53pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/10 "2024-11-22T12:53:34Z")

</div>

Thanks!

Yeah, that's pretty good, but I'm hoping to avoid the `syntax-local-eval` (which is kind of worse than `syntax-local-value` in sorawee's answer). It seems to me that a simpler check should be possible — but I'm not sure what.

---

<div class="post-metadata">

**Author:** ![Laurent.O](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/laurent.o/32/18_2.png) [@Laurent.O](https://racket.discourse.group/u/Laurent.O)\
**Post date:** [November 22, 2024, 1:08pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/11 "2024-11-22T13:08:18Z")

</div>

Oh, actually it appears I was mistaken: `syntax-local-value` may be the right thing to do, just not in the way sorawee used it first.

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

(define-syntax (thingy stx)
  (syntax-parse stx
    [(_ (op:id arg:expr ...))
     #:when (not (syntax-local-value #'op (λ () #f))) ; is this a syntax object?
     #'(let ([vals (list arg ...)])
         (list (apply op vals) ; can't apply `and` here
               (map cons (list 'arg ...) vals)))
     ]
    [(_ ex:expr)
     #''second-branch]))

(thingy true) ; 'second-branch

(thingy (and (= 1 1) (= 2 3))) ; 'second-branch

(thingy (= 2 3)) ; '(#f ((2 . 2) (3 . 3)))

```

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [November 22, 2024, 3:40pm UTC](https://racket.discourse.group/t/in-macro-is-object-a-macro-or-a-procedure/3323/12 "2024-11-22T15:40:19Z")

</div>

I think `syntax-local-value` will work, but it may be more conservative than you would like: for example, it would put anything with the keyword-procedure optimization in the has-a-transformer-binding case.

You might want to `local-expand` the expression and look for `#%plain-app` (or maybe you also want to recognize `#%app` specially, or maybe add `#%expression` somewhere, or …).
