[racket] Another Canonical Use of Macros?
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