Julia 与 Python 等语言的区别在于,Julia 允许您在代码被评估之前拦截代码。宏只是用 Julia 编写的函数,可让您访问该代码并在其运行之前对其进行操作。此外,它不是将代码视为字符串(如 "f(x)"),而是作为 Julian 对象提供(如 Expr(:call, :f, :x))。
它允许的许多事情在 Python 中是不可能的。主要有:
您可以在编译时做更多的工作,提高性能
这方面的两个很好的例子是正则表达式和 printf。这两者都采用某种格式规范并以某种方式对其进行解释。现在,这些可以相当直接地实现为函数,如下所示:
match(Regex(".*"), str)
printf("%d", num)
问题在于这些规范必须在每次运行语句时重新解释。每次解释器遍历此块时,必须将正则表达式重新编译成状态机,并且必须通过迷你解释器运行格式。另一方面,如果我们将这些实现为宏:
match(r".*", str)
@printf("%d", num)
然后r 和@printf 宏会在编译时截取代码,并运行各自的解释器然后。正则表达式变成了一个快速状态机,@printf 语句变成了一个简单的println(num)。在运行时完成了最少的工作,因此代码非常快。现在,其他语言能够提供快速的正则表达式,例如,通过为其提供特殊语法——但事实上它们在 Julia 中没有特殊情况,这意味着开发人员可以在自己的代码中使用相同的技术。
你可以为几乎任何东西制作迷你编译器
带有宏的语言往往具有更强大的嵌入式 DSL,因为您可以随意更改语言的语义。例如,代数建模语言JuMP.jl。 Clojure 也有一些很好的例子,比如它嵌入的logic programming language。 Mathematica.jl 甚至在 Julia 中嵌入了 Mathematica 的语义,这样你就可以编写像 @Integrate(log(x), {x,0,2}) 这样的非常自然的符号表达式。您可以在 Python 中将其伪装成某种程度(SymPy 做得很好),但没有那么干净或高效。
如果这不能说服您,请考虑有人设法在纯 Julia 中使用宏实现了 interactive Julia debugger。在 Python 中尝试一下。
编辑:另一个在其他语言中比较困难的例子是Cartestian.jl,它可以让您编写跨任意维数数组的通用算法。