Overthunk

Macros Again + 4Clojure

Jul 12, 2020


Contents

What I learned Today

I finished up Chapter 8 today. Well, more like sped through it. Having gone through macros with Clojure from the Ground Up, I was inclined to get through the chapter quickly. But despite that there were still some interesting things I learned from the chapter.

Writing Macros

(+ 1 2)
;; => 3

'(+ 1 2)
;; => (+ 1 2)
'+
;; => +

`+
;; => clojure.core/+

'(+ 1 2)
;; => (+ 1 2)

`(+ 1 2)
;; => (clojure.core/+ 1 2)

`(+ 1 ~(inc 1)) ;; using ~ inside ` unquotes the form
;; => (clojure.core/+ 1 2)

(list '+ 1 (inc 1))
;; => (+ 1 2)

`(+ 1 ~(inc 1))
;; => (clojure.core/+ 1 2)

Clearly the syntax-quoted version is more concise.

Macros receive unevaluated, arbitrary data structures as arguments and return data structures that Clojure evaluates.

Unquote splicing unwraps a seqable data structure, placing its contents directly within the enclosing syntax-quoted data structure.

`(+ ~(list 1 2 3))
;; => (clojure.core/+ (1 2 3))

`(+ ~@(list 1 2 3))
;; => (clojure.core/+ 1 2 3)

Gotchas

  1. Variable Capture - Macro introduces a binding that overwrites an existing binding. Soln: gensym -> produces a unique symbol that can be bound to variables inside macros used to prevent variable capture within macros.
  2. Double Evaluation - When a form passed to a macro as an argument gets evaluated more than once. Soln: Bind the repeating form to a gensym within a let and use that instead of the form

4Clojure

I’m getting a hang of solving these Medium problems. Today I managed to get through a couple more -

No. 50 Split by Type Write a function which takes a sequence consisting of items with different types and splits them up into a set of homogeneous sub-sequences. The internal order of each sub-sequence should be maintained, but the sub-sequences themselves can be returned in any order (this is why ‘set’ is used in the test cases).

(defn spl-by-type
  [xs]
  (into #{}
        (vals
         (reduce
          (fn [acc v]
            (assoc acc (type v)
                   (if-let [x (get acc (type v))]
                     (conj x v)
                     [v])))
          {} xs))))

No. 55 Count Occurences Write a function which returns a map containing the number of occurences of each distinct item in a sequence.

(defn occur
  [xs]
  (->> xs
       distinct
       (reduce (fn [acc a] (assoc acc a (count (filter #(= a %) xs)))) {})))

Takeaways

Macros are fun. They can be used for a lot of things. But maybe don’t use them for everything.

Today’s tally -