A language that is lazy by default lets you control the evaluation of arguments. Ordinarily, they're not evaluated, and if you force them they are.
However, macros are not just about whether to evaluate -- but about exposing the internal syntactic structure of the arguments.
In Haskell, using laziness you can implement control flow, short-circuiting, etc. If you want functions that work with the syntactic structure of their arguments, you need heavier machinery:
* Thick DSLs: Define explicit AST types and have a DSL that explicitly constructs those AST's.
* Template Haskell (the arguments' syntax has to be in ordinary Haskell)
* Quasiquotes (Need to parse strings)
I think the need for exposed syntax is relatively rare (e.g: a function that evaluates and shows a trace of the evaluation). In those cases, I think explicit AST types work pretty well, as Haskell has extremely light-weight syntax for constructing user-defined data types.
Without access vocal inflection, I'm not sure if you're intending to argue, or expand. So, I'm gonna go with continuing to expand on the point.
Simple laziness does not allow you the same level of control over evaluation as vau expressions do. A vau expression can choose to evaluate it its arguments exactly once (like call-by-value), exactly as many times as they're used (like call-by-name), only if they are used (like laziness), as many times as you feel like, in a different environment than the calling context, or not at all, and can make that decision independently for every argument.
In Kernel's implementation at least, unevaluated operands are AST types that can be poked and modified, not opaque values like lazily-evaluated operands. As a result, vau expressions can be used to implement macros, both the hygenic and non-hygenic variety, and the language need not define quoting or quasiquoting because those features can also be implemented within vau expressions.
Vau expressions seem to play havoc with static analysis, though, so there are good arguments for actually having some of those things as built-in language features rather than just building everything as a standard library.
I was expanding (with a slight correction about macros doing more than just controlling evaluation).
Haskell-style laziness comes with purity, where it does not matter much whether something is evaluated once or many times. It does matter if it is evaluated 0 or more though (due to non-termination and exceptions).
The opacity of values is what I meant by macros also exposing the syntax as opposed to just controlling evaluation.
However, macros are not just about whether to evaluate -- but about exposing the internal syntactic structure of the arguments.
In Haskell, using laziness you can implement control flow, short-circuiting, etc. If you want functions that work with the syntactic structure of their arguments, you need heavier machinery:
* Thick DSLs: Define explicit AST types and have a DSL that explicitly constructs those AST's.
* Template Haskell (the arguments' syntax has to be in ordinary Haskell)
* Quasiquotes (Need to parse strings)
I think the need for exposed syntax is relatively rare (e.g: a function that evaluates and shows a trace of the evaluation). In those cases, I think explicit AST types work pretty well, as Haskell has extremely light-weight syntax for constructing user-defined data types.