Reading: Clojure for the Brave – ch8


  • literal forms: things that eval to themselves
    • boolean, keys numbers, strings, data-structures (map, list, vector)
  • symbol:
    • names given to functions, data, macros, etc.
    • symbols are resolved by
      • is special form? like if
      • has local binding (from function-param or let)
      • has namespace mapping (using def)
      • invalid symbol
    • a symbol can point to a function; at parse-time, a symbol and the value it binds to are different even if the symbol is passed around where a function is expected. for example: (map inc [1 2]):
    • The symbol map refers to the map function, but it
      shouldn’t be confused with the function itself.
      The map symbol is still a data structure, the same
      way that the string “fried salad” is a data structure,
      but it’s not the same as the function itself
  • Special forms
    • things that cannot be implemented with functions
    • for example with (if (empty? []) true false) you don’t want to each
      element of the outer-most list, hence a special form is needed.
    • if, quote are examples
    • similarly def, let, loop, fn, do, recur.
  • Macros
    • You can place a macro at the beginning of a list, instead of a
      symbol/special-form, which allows you to change how rest of the data-structure is evaluated.
    • They are executed in between the reader and the evaluator—so they can manipulate the data structures that the reader spits out and transform
      with those data structures before passing them to the evaluator.
    • the param is not evaluated when passed to macro body; instead a raw list data-structure is sent. This is different from a function body (where it is evaluated.
    • Similarly, the return value of a macro IS evaluated, whereas that of a function is NOT.

Writing macros

  • You can have overloaded/multi-airity macros just like functions
    • Read the sections “Macros All the Way Down” and Double Eval in the same document
    • If you need to evaluate values of some sub-expression, you have to quote symbols you are declaring in your macro, otherwise it’ll try to eval a symbol that isn’t created yet. This is done like this:
(defmacro my-print
		  (list 'let ['result expression]
				(list 'println 'result)
  • syntax quote
    • The syntax is to prefix with ` character, which fully qualifies the quoted symbol
> `+
; => clojure.core/+

> 'clojure.core/+
; => clojure.core/+

> '+
; => +
  • You can unquote a single expression inside a syntax-quoted expression
    by prefixing with a ~. This is kind of like string-interpolation
> `(+ 1 ~(inc 1)) 
; => (clojure.core/+ 1 2)
  • Unquote-splicing (~@) works this way
macro-trials.core> `(+ ~@(list 1 2 3))
(clojure.core/+ 1 2 3)

macro-trials.core> `(+ ~(list 1 2 3))
(clojure.core/+ (1 2 3))