代码之家  ›  专栏  ›  技术社区  ›  Al Chou

Clojure宏创建函数的同义词

  •  6
  • Al Chou  · 技术社区  · 16 年前

    对于任何真正知道如何在任何Lisp中编写宏的人来说,这可能是一个简单的方法。我想能够定义函数名的同义词。我一直在复制粘贴hacking core.clj来做这件事,但我不想永远做这样的笨蛋!显然,将对Synoym函数的调用重写为对原始函数的调用的宏是正确的方法。

    2 回复  |  直到 11 年前
        1
  •  13
  •   G__    16 年前

    如果我理解你的问题,有一个更简单的方法:将新符号定义为旧函数。

    user=> (def foo +)
    #'user/foo 
    user=> (foo 1 2) 
    3
    

    def的性能也优于宏观方法:

    (defmacro foo2 [& args]
      `(+ ~@args))
    

    然后,foo2实际上是+的别名,其行为方式(重写为+)完全相同,除了使用宏时必须返回值的限制之外。

    如果希望“alias”的行为与原始函数的行为完全相同(在相同的上下文中也可以调用),则需要使用def重命名该函数。

    user=> (def foo +)
    
    user=> (defn foo1 [& args]
             `(+ ~@args))
    
    user=> (defmacro foo2 [& args]
             `(+ ~@args))
    
    user=> (time (dotimes [n 1000000] (foo 1 n)))
    "Elapsed time: 37.317 msecs"
    
    user=> (time (dotimes [n 1000000] (foo1 1 n)))
    "Elapsed time: 292.767 msecs"
    
    user=> (time (dotimes [n 1000000] (foo2 1 n)))
    "Elapsed time: 46.921 msecs"
    
        2
  •  2
  •   galdre    11 年前

    宏现在更快了

    在我的一个项目中,我开始了重命名Clojure的一些核心功能的任务(非常愚蠢)。我玩得很开心( fn 变成 λ , loop 变成 ⟳ 但我发现自己对表演很好奇。格雷格五年前的完美答案现在,我想,部分是错误的。我用的是Clojure 1.5.1。

    初学者:

    user=> (defn foo1 [& args] `(+ ~@args))
    #'user/foo1
    user=> (foo1 1 2 3 4)
    (clojure.core/+ 1 2 3 4)
    

    这绝对不是你想要的。此外,现在看来宏绝对是最快的选择。我复制了格雷格的实验,得到了完全不同的结果。你在下面看到的时间都是十次跑步中最好的一次:

    user=> (def foo +)
    #'user/foo
    user=> (defn foo1 [& args] (apply + args))
    #'user/foo1
    user=> (defmacro foo2 [& args] `(+ ~@args))
    #'user/foo2
    user=> (time (dotimes [n 1000000] (+ 1 n)))
    "Elapsed time: 53.401812 msecs"
    user=> (time (dotimes [n 1000000] (foo 1 n)))
    "Elapsed time: 135.675486 msecs"
    user=> (time (dotimes [n 1000000] (foo1 1 n)))
    "Elapsed time: 494.770352 msecs"
    user=> (time (dotimes [n 1000000] (foo2 1 n)))
    "Elapsed time: 53.509264 msecs"
    

    另外,我认为方法之间的差异变得微不足道,因为函数的作用更大。这是我最初运行的实验,我发现它们之间没有区别:

    user=> (defmacro α [& body] `(reduce ~@body))
    #'user/α
    user=> (defn β [& body] (apply reduce body))
    #'user/β
    user=> (def γ reduce)
    #'user/γ
    user=> (time (dotimes [n 10000] (reduce + (range n))))
    "Elapsed time: 5466.920266 msecs"
    user=> (time (dotimes [n 10000] (α + (range n))))
    "Elapsed time: 5474.532622 msecs"
    user=> (time (dotimes [n 10000] (β + (range n))))
    "Elapsed time: 5491.337517 msecs"
    user=> (time (dotimes [n 10000] (γ + (range n))))
    "Elapsed time: 5456.271967 msecs"
    

    最后,你要找的可能是 defalias clojure.contrib.def . 我没有这方面的经验。