Regarding compiler macros:

I've experimented it for a while in Gauche, starting from CL-style define-compiler-macro.
What I found is that allowing separate definitions for the syntax version and the procedural version could have undesired consequences.

* (define foo ...)  is a valid definition with or without (define-overloaded-syntax foo ...),  so even if (define-overloaded-syntax foo ...) hasn't been seen by the compiler, it just accept (define foo ...) form as it is.  If the programmer accidentally misplaced define-overloaded-syntax form, or change the name of one but not the other, it'd be a difficult-to-find bug.

* The procedural version doesn't need to delegate the definition to the macro version entirely.  There are valid use cases you want to have "meat" in the procedural version of the definition.

    - If you want to dispatch by the number of arguments, you have to write it in procedure definition, since you can't say (define (foo . x) (apply foo x)) to invoke macro version of foo.
    - One of the most useful applications of the compiler macros is to look at the source form and emit specialized code in certain cases, but leave it intact in other cases so that the procedure version handles it.  In which case you write the generic code in procedure definition, while specialized code in the macro definition.

If the definition of macro version and procedure version can be separated, it is prone to a bug when someone edits one version but forget to updates the other in future.  (I've bitten by it hard several times working in CL.)

* A macro is bound to an identifier at compile-time.  It limits the opportunities of optimization.  For example, if you have code something like this:

   (let ((op fx+))
      ...
      (op i j))

Wouldn't you want to expand (op i j), given that op isn't mutated?  The compiler can do that, but it deviates from the semantics of macro, since in '(op i j)', op is not a macro keyword.

Observing those, I introduced a feature in upcoming Gauche (0.9.6) such that:

- Internally, a macro transformer for the compiler macro is coupled with the procedure object, not to the identifier.  This allows the compiler to apply transformer after analyzing value propagation.
- We have one form that defines both the procedure body and the macro transformer in one place (define-inilne/syntax).

I'm not sure how much it can be generalized to other Scheme implementations (esp. in the first point), but I'd say having one form to define both procedure body and macro transformer would make things easier in general.



On Mon, May 15, 2017 at 6:40 AM, John Cowan <xxxxxx@ccil.org> wrote:

On Mon, May 15, 2017 at 12:27 PM, Per Bothner <xxxxxx@bothner.com> wrote:

(define-overloaded-syntax fx+ ...)
(define (fx+ x y) (fx+ x y))

I agree on all points.  If anyone can come up with a better name, go for it.

-- 
John Cowan          http://vrici.lojban.org/~cowan        xxxxxx@ccil.org
Take two turkeys, one goose, four cabbages, but no duck, and mix them
together. After one taste, you'll duck soup the rest of your life.
        --Groucho