maybe to support semantics "this is an if statement" could be some kind of metadata on the macro i suppose?
> (and a b c)
> (and* a b c)
Can you tell by looking that the the first is a macro and the second is a function? The first short circuits and evaluates only the argument forms it needs and the second always evaluates all three. That's a big difference, and not at all obvious from the syntax. In fact, it's hidden by the syntax, because the syntax is exactly the same for each.
Macros are part of the power of Lisp, but they change the normal rules of evaluation (the semantics) in ways that are not necessarily obvious unless you know the specific definitions behind each symbol in function position.
This is the TXR Lisp interactive listener of TXR 268.
Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
1> (special-operator-p 'and)
t
2> (fboundp 'and)
t
3> (fun and)
#<intrinsic fun: 0 param + variadic>
4> (and 23 nil (prinl 42))
nil
5> (call 'and 23 nil (prinl 42))
42
nil
6> [and 23 nil (prinl 42)]
42
nil
7> [mapcar if '(nil t t nil) '(1 2 3 4) '(a b c d)]
(a 2 3 d)
8> (if t (prinl 'true) (prinl 'false))
true
true
9> [if t (prinl 'true) (prinl 'false)]
true
false
true
If we use the functional brackets, all arguments are evaluated the same way, and the leftmost value is treated as a callable object applied to the remaining values.A symbol in the leftmost position of [...] is never treated as a macro (other than symbol macro) or special operator, even if it has a such a binding.
For me this was the biggest challenge when I was introduced to lisp: everything is just a list. Powerful, yes, but in other languages the ground felt firmer underneath my feet when I knew a class was a class, a struct was a struct, and array was an array, all with their own unique syntax. In lisp everything just looks the exact same. That is part of why it is so powerful, but at the cost of semantical references that can help users understand a lisp program.
---