This is only ~90% likely to be correct, since it's second-hand information and I don't use LISP actively.
A LISP macro is a syntax transformation. It lets you write code in the way you want to, instead of whatever level of abstraction you used to have.
I'm not sure about 'partially formed' code output, but 'partially formed' input is definitely possible. The way to invoke a LISP macro need not be valid LISP. In short, LISP macros excel at creating domain-specific languages.
In my Lisp-esque language I use a temporary macro to automate the creation of some similar standard library procedures. This happens at runtime in the stdlib source file that is loaded:
# Define procedures named int? float? etc that test the type of a value.
(def def-type-predicate (mac (type-name)
`(def ,(string-to-symbol (join "" $type-name "?"))
(proc (x) (eq? (type x) ',type-name)))))
(def-type-predicate int)
(def-type-predicate float)
(def-type-predicate bool)
(def-type-predicate string)
(def-type-predicate symbol)
(def-type-predicate file)
(def-type-predicate nil)
(def-type-predicate pair)
(def-type-predicate procedure)
(def-type-predicate macro)
(zap def-type-predicate)
The crucial thing about what happens there being that the (def foo? ...) value produced by each macro invocation then gets evaluated in the root/top-level environment and so results in a "global" procedure definition. Using them:
But it's nice to have single-parameter ones for FP list stuff. I suppose that 2-parameter version could have their order swapped and do partial application on top of it.
Anyway, was just sharing something I had fun making. No language wars intended.
A LISP macro is a syntax transformation. It lets you write code in the way you want to, instead of whatever level of abstraction you used to have.
I'm not sure about 'partially formed' code output, but 'partially formed' input is definitely possible. The way to invoke a LISP macro need not be valid LISP. In short, LISP macros excel at creating domain-specific languages.