Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inlining a function with Clojure macros

More out of curiousity that anything else (but with the expectation that it might occasionally be a useful trick for performance tuning), is it possible to use Clojure macros to "inline" an existing function?

i.e. I would like to be able to do something like:

(defn my-function [a b] (+ a b))

(defn add-3-numbers [a b c] 
  (inline (my-function 
    a 
    (inline (my-function 
      b 
      c)))))

And have it produce (at compile time) exactly the same function as if I had inlined the additions myself, such as:

(defn add-3-numbers [a b c] 
  (+ a (+ b c)))
like image 938
mikera Avatar asked Dec 18 '10 11:12

mikera


1 Answers

In case you didn't know, you can define inlined functions using definline

(doc definline)
-------------------------
clojure.core/definline
([name & decl])
Macro
  Experimental - like defmacro, except defines a named function whose
  body is the expansion, calls to which may be expanded inline as if
  it were a macro. Cannot be used with variadic (&) args.
nil

Also checking the source,

(source definline)
-------------------------
(defmacro definline
  [name & decl]
  (let [[pre-args [args expr]] (split-with (comp not vector?) decl)]
    `(do
       (defn ~name ~@pre-args ~args ~(apply (eval (list `fn args expr)) args))
       (alter-meta! (var ~name) assoc :inline (fn ~name ~args ~expr))
       (var ~name))))

definline simply defines a var with meta-data {:inline (fn definition)}. So although its not exactly what you were asking but you can rebind the var with new metadata to get inlined behavior.

like image 59
bmillare Avatar answered Oct 25 '22 12:10

bmillare