Usually, I am pretty careful about adding parenthesis in Racket.
Yes, you are right to be careful. It usually makes a difference.
In your case, however, it doesn't seem to make a difference, because you are creating an overly simple macro that happens to expand in the same way whether the macro is invoked as a regular transformer or as an identifier macro.
I was expecting something like a #procedure for the first call on foo.
I want to address this first. Macros transform your program syntactically. For example, I can write a macro flip that flip the operands, so that
(flip foo 1 (let) bar baz 2)
is expanded (not evaluated) to:
(2 baz bar (let) 1 foo)
Again, I want to emphasize that this is a program transformation, like how you edit the code with your editor.
Now, let's write some actual macros:
(define-syntax bar
(lambda (stx)
(cond
[(equal? (syntax->datum stx) '(bar abc def)) #'(+ 1 1)]
[else #'(+ 2 2)])))
(bar abc def) ;== expands => (+ 1 1) == evaluates => 2
(bar 42 (abc) qqq) ;== expands => (+ 2 2) == evaluates => 4
(bar) ;== expands => (+ 2 2) == evaluates => 4
In the above macro, it checks if the input syntax is syntactically (bar abc def). If so, it transforms to (+ 1 1). Otherwise, it transforms to (+ 2 2).
All of these is to show you that it is unreasonable to expect a macro to result in "#procedure" (of course, unless the macro expands to a lambda), since what macro does is transforming syntax. It doesn't create a procedure.
The final mystery is what's going on with bare foo. Let's create a macro baz to understand that:
(define-syntax baz
(lambda (stx)
(cond
[(equal? (syntax->datum stx) 'baz) #'1]
[(equal? (syntax->datum stx) '(baz)) #'2]
[else #'3])))
baz ;== expands => 1
(baz) ;== expands => 2
(baz 10) ;== expands => 3
It turns out that a bare identifier could also be a macro!
Now, consider your foo:
(define-syntax foo
(lambda (stx)
(syntax "I am foo")))
It's a transformation that ignores its operands, and always expands to "I am foo".
So:
(foo 1 2 3) ;== expands => "I am foo"
(foo x y z) ;== expands => "I am foo"
(foo) ;== expands => "I am foo"
foo ;== expands => "I am foo"
Note that in most macros, we use pattern matching to extract operands. Pattern matching can raise a syntax error when the input syntax doesn't match any pattern. This, for example, allows us to create a macro that doesn't allow it to be used as an identifier macro.
(define-syntax food
(lambda (stx)
(syntax-case stx ()
;; match when there is a parenthesis around the macro
[(_ ...) #'1])))
(food) ;=> 1
food ;=> food: bad syntax