问题 使用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)))

1884
2017-12-18 11:01


起源

你看看了吗? apply 功能? clojuredocs.org/clojure_core/clojure.core/apply - edbond
apply在运行时动态工作,我正在寻找在编译时执行内联的东西.... - mikera
(read-string (clojure.repl/source-fn `my-function)) 似乎是一个很好的起点! - vemv


答案:


如果您不知道,可以使用定义内联函数 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 ~@pre-args ~args ~(apply (eval (list `fn args expr)) args))
       (alter-meta! (var ~name) assoc :inline (fn ~name ~args ~expr))
       (var ~name))))

definline 简单地定义一个 var 与元数据 {:inline (fn definition)}。因此,尽管它不是您要求的,但您可以使用新元数据重新绑定var以获得内联行为。


14
2017-12-18 16:25



有用的链接 - 在许多情况下,这绝对看起来像一个有用的工具。与我正在寻找的关键区别在于它似乎要求将函数明确定义为内联,而我希望能够内联任意函数 - mikera
我没有考虑实施它,但我暗示了一个潜在的解决方案。您可以尝试使用包含:inline标记的元数据编写将函数var重新绑定为一的宏。需要解决的关键问题是确保重新绑定在编译时而不是运行时完成。 - bmillare