I'm starting out with Clojure, which is also my first lisp. There's obviously a lot to take in, and in an attempt to lessen the cognitive load, I try to find the parts which I can safely ignore (for now).
Can one safely treat forms with macros and forms with built-ins the same, or are there pitfalls that will spring up later?
In other words, will I ever run into a situation where I need to know that (defn f1 [])
expands to
(def f1 (.withMeta (clojure.core/fn f1 ([])) (.meta (var f1))))
I'm a Clojure newbie myself, but a little more time trying out the language.
I can say Clojure built-in macros are very safe in that you can use them without even knowing they are macros.
In particular, because Clojure focuses much more on immutability than Common Lisp, it's harder for you to fall into a bug caused by a missbehaving macro.
So, no, you won't run into a situation where you need to know about the internals of a built-in macro. But if you want to figure out the internals of your own custom macro, there's always macroexpand.
Macros in general compose very differently. Macros are not "first class citizens": you can't pass them to
map
etc., you can't store them in variables and you can'tapply
them to a list of arguments. Initially you don't need to worry about these because they will obviously not work: a subtle, hard-to-detect error would be a lot more troubling. If you try to runthe fact that if is not a function will become very apparent. Just keep in mind that macros are not functions and you should be just fine :)
PS: macros are
(fn (fn (fn :-D) :^P) :O)
In almost all cases you can completely ignore the distinction. (and in fact you have, since fn isn't a built in either - it's a macro expanding to fn*)
The only exception I've come across is that macros and built-ins behave differently if you try to redefine them. Just don't redefine any existing functionality and you'll be fine treating them the same.