Clojure Koans 24 Macros Notebook

Original Clojure Koans: https://github.com/functional-koans/clojure-koans/

Clojure Koans Spoilers Alert

Preface: An experienced Clojure developer friend has told me to not use macros for now, loosely paraphrasing them: "Macros are an advanced technique, best to be revisited with more experience, a clear need, and defined use-case."

{:deps {org.clojure/clojure {:mvn/version "1.10.1"}
        ;; complient is used for autocompletion
        ;; add your libs here (and restart the runtime to pick up changes)
        compliment/compliment {:mvn/version "0.3.9"}}}
deps.edn
Extensible Data Notation
{:hello (clojure-version)}
0.1s
Clojure

Initial Thoughts

Macros seem foreign and new to me as a first time LISPer. What new powers will they help me unlock as a programmer?

(defmacro hello [x]
    (str "Hello, " x))
Clojure
(defmacro infix [form]
    (list (second form) (first form) (nth form 2)))
Clojure
;; note: unused-public-var linter warning from clojure-lsp
(defmacro infix-concise [form]
    `(~(second form) ; Note the syntax-quote (`) and unquote (~) characters!
       ~(first form)
       ~(nth form 2)))
;; question 24008: What exactly does the "unquote" (~) character do?
;; question 24009: What exactly does the "syntax-qyote" (`) character do?
;; question 24010: How advanced exactly are macros, and what learning prerequisites are appropriate/suitable?
;; question 24011: What are great use cases for macros?
;; question 24012: What are common pitfalls for first time macro writers?
Clojure
(defmacro recursive-infix [form]
    (cond (not (seq? form))
          form
          (= 1 (count form))
          `(recursive-infix ~(first form))
          :else
          (let [operator (second form)
                first-arg (first form)
                others (rest (rest form))]
              `(~operator
                   (recursive-infix ~first-arg)
                   (recursive-infix ~others)))))
Clojure
;; "Macros are like functions created at compile time"
(= "Hello, Macros!" (hello "Macros!"))
;; ~~question 24001: What is the significance (and consequences) of macros being created at compile time?~~
;; answer 24001a: High level question, too broad, and not immediately helpful at this stage.
;; skill 24001: Invoke a macro
Clojure
;; "I can haz infix?"
(= 10 (infix (9 + 1)))
;; description: The `infix` macro is used to take in the arguments `9`, `+`, and `1` to execute the addition operation `nine plus one` to get a result of ten. The text above of "I can haz infix?" is a reference to an Internet meme where the grammatically correct English would be be "Can I have infix?"
;; question 24002: Is infix notation useful or helpful to Clojure programmers?
;; answer 24002a: Perhaps when converting code from other languages or regular text... Though I'd still guess no.
;; skill 24002: Invoke a macro that enables non-(Clojure-)standard syntax
Clojure
;; "Remember, these are nothing but code transformations"
(= '(+ 9 1) (macroexpand '(infix (9 + 1))))
;; question 24003: What exactly is happening here?
;; question 24004: Why is `infix` quoted?
;; answer 24004a: `infix` is quoted to prevent code execution from
;;    happening so that way the `macroexpand` can correctly expand `infix`.
;; question 24005: What is `macroexpand`?
;; answer 24005a: From the docs:
;;    "Repeatedly calls macroexpand-1 on form until it no longer represents
;;    a macro form, then returns it.  Note neither macroexpand-1 nor
;;    macroexpand expand macros in subforms."
;; question 24006: What is `macroexpand-1`?
;; answer 24006a: TBD...
;; skill 24003: Expand a macro by using `macroexpand`
Clojure
;; "You can do better than that - hand crafting FTW!"
(= '(* 10 2) (macroexpand '(infix-concise (10 * 2))))
;; skill 24004: Write your own custom macro
Clojure
;; "Things don't always work as you would like them to... "
(= '(+ 10 (2 * 3)) (macroexpand '(infix-concise (10 + (2 * 3)))))
;; question 24007: Is this Koan exercise in the wrong order?
Clojure
;; "Really, you don't understand recursion until you understand recursion"
(= 36 (recursive-infix (10 + (2 * 3) + (4 * 5))))
Clojure

Closing Thoughts

While excited to try using macros, I am thinking, after speaking with a Clojure friend, that I am best off to indeed "shelve them for now." I wonder how many other Clojure Koans sections, as well as the "well advertised benefits of Clojure" (e.g. as listed on clojure.org) are too advanced/complex for a Clojure/LISP initiate to use correctly/effectively.

;; skill 24005: Rewrite a macro as a function
Clojure

To-Do's

  • [ ] Add research here to helpful macro use-cases

  • [ ] Consider (brainstorm, research) how might I build my macro thinking skills before I need to use them

Runtimes (1)