2010-12-18 51 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