2010-12-18 71 views
11

更多的是因为好奇心,其他任何东西(但是期望它偶尔会成为性能调优的有用技巧),是否可以使用Clojure宏来“内联”现有函数?使用Clojure宏内联函数

即我希望能够做一些事情,如:

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

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

而且有它产生(在编译时)功能完全一样,如果我已经内联的补充自己,如:

(defn add-3-numbers [a b c] 
    (+ a (+ b c))) 
+0

你看过“应用”功能吗? http://clojuredocs.org/clojure_core/clojure.core/apply – edbond 2010-12-18 17:02:45

+1

在运行时动态地应用工作,我正在寻找在编译时执行内联的东西.... – mikera 2010-12-20 12:31:44

+0

'(read-string(clojure.repl/source-fn \'my-function))''看起来是一个很好的起点! – vemv 2013-01-14 00:48:49

回答

14

如果你不知道,你可以用定义内联函数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 

还检查源,

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

definline简单地定义与元数据{:inline (fn definition)}一个var。因此,虽然它不完全是你所要求的,但你可以用新的元数据重新绑定var来获取内联行为。

+0

有用的链接 - 在许多情况下,这绝对是一个有用的工具。与我正在寻找的关键区别在于,它似乎要求将函数明确定义为内联,而我希望能够内联任意函数 – mikera 2010-12-20 12:35:06

+0

我还没有考虑实现它,但我暗示了解决方案。您可以尝试编写一个将函数var重新绑定到包含inline标记的元数据的宏。需要解决的关键问题是确保重新编译是在编译时而不是运行时完成的。 – bmillare 2010-12-22 18:17:03