Let me try to make the point another way. If I have a function call (f arg), arg is evaluated in the current environment. If I have a macro call (m arg), the macro can create arbitrary computational contexts for arg: it may refer to variables that do not occur in the current computational context, its evaluation may be delayed until varius I/O operations are performed, or various updates to global variables are performed, or some other such thing. Not only that, we can do sophisticated transformations on arg, eg. we might perform a CPS transformation on the arguments through a structural recursion on the given code fragments (Jeffrey Mark Siskind's Screamer code, integrating a constraint-solving language into Common LISP, is based on this technique).