Maybe this will help see the full scope of the power of macros: macros receive their arguments as an AST (i.e. a list) and are free to transform it as they please; they also have full access to the host language and are free to implement a type system checker that walks code and checks that all the types match. There are no restrictions here - the type checker would be regular scheme code that would be wrapped into a macro simply to make it run at compile time. So there's nothing less powerful about macros at all. It's just code that runs at a different stage (compile-time instead of run-time). After macros, in terms of power, you have reader macros, that receive their arguments as raw text and are free to turn it into any AST.