[racket] Another Canonical Use of Macros?

From: John Clements (clements at brinckerhoff.org)
Date: Mon Nov 25 12:54:52 EST 2013

On Nov 23, 2013, at 5:46 AM, Matthias Felleisen wrote:
>> - abstracting over things that are not expressions.
>> 
>> For instance:
>> 
>> cmp_impl!(impl Eq, eq, ne)
>> cmp_impl!(impl TotalEq, equals)
>> cmp_impl!(impl Ord, lt, gt, le, ge)
>> cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering)
>> 
>> Each of these expands into a top-level "impl" declaration, extending implementations of, e.g., Ord, from type T to type Ratio<T>. 
> 
> 
> Like someone else said, I would classify this kind of macro as a 'binding form' macro assuming you're using 'declaration' in the standard sense. 

Hmm... well, they're not binding any new identifiers; they're just declaring that this type implements this trait.  

Moreover, I think there's a clear distinction between motivations:

1) 'let' can't be a function call because function calls can't bind new identifiers in the environment of the caller.
2) Rust's 'impl' -- and many other forms in that language -- can't be abstracted over because they're not in expression positions; this is the same thing that prevents you from abstracting over "define-struct", except with a macro.  Indeed, I can't even abstract over function definitions at the top level of a module.

The "less enlightened" a language is, the more such non-expression-position program fragments there are, and the more valuable macros become.

Moreover -- and this is true in Racket as well -- there's often a deliberate rationale at work here; the designers want certain things to be apparent at compile time, so that the compiler can do a better job. When these decisions get baked into the syntax, then macros become the only way to abstract over them.

John



Posted on the users mailing list.