1 minute read

Code

;; macro_based_decorator.clj

;; 3. Macro-based Decorator (More Python-like Syntax)

(defmacro decorate [decorator & body]
  (let [form (first body)]
    (if (and (list? form) (= 'fn (first form)))
      ;; Anonymous function: (decorate decorator (fn [x y] (+ x y)))
      `(~decorator ~form)
      ;; Named function: (decorate decorator (add [x y] (+ x y)))
      (let [[fname args & fbody] form]
        `(def ~fname (~decorator (fn ~args ~@fbody)))))))

;; Define decorators
(defn log-calls [f]
  (fn [& args]
    (println (str "Calling function with args: " args))
    (let [result (apply f args)]
      (println (str "Result: " result))
      result)))

(defn timer-decorator [f]
  (fn [& args]
    (let [start (System/nanoTime)
          result (apply f args)
          end (System/nanoTime)]
      (println (str "Execution time: " (/ (- end start) 1000000.0) " ms"))
      result)))

;; Usage examples:

;; Named function with decorator
(decorate log-calls
          (add [x y]
               (+ x y)))

(macroexpand '(decorate log-calls (add [x y] (+ x y))))
;;=> (def add (log-calls (clojure.core/fn [x y] (+ x y))))

;; Test the decorated function
(add 5 3)

;; Or with anonymous function
(def my-add (decorate timer-decorator
                      (fn [x y] (+ x y))))

(macroexpand '(decorate timer-decorator
                        (fn [x y] (+ x y))))
;;=> (timer-decorator (fn [x y] (+ x y)))

;; Test the anonymous decorated function
(my-add 10 20)

Updated: