宏是一种对编程语言进行编程的方法。简单地说,宏是一种生成程序代码的方式,而不是一直自己编写。
另一方面,语言结构(有时称为“特殊形式”)是长生不老药本身的核心。过度简化可能是 if 的实现不是在 Elixir 中完成的,而是在 Elixir 实现的语言中完成的。
假设您想使用提到的unless。
编辑:unless 在 Elixir 中可用。但让我们假设其余部分不是。
在 Elixir 中,该语言中没有 unless。 José Valim 没有实施它。但是你总是可以写一些具有相同语义的东西:一个否定的if。
我们希望喜欢拥有这个,但我们不:
unless sun_shines() do
open_umbrella()
end
但是我们只有一个if和一个not,所以我们可以这样写:
if not sun_shines() do
open_umbrella()
end
其次,宏是一种特殊的函数,但它的参数是代码,执行宏的结果也是代码。假设我们有unless 宏,它接受一个条件(即sun_shines())和一个主体(即open_umbrella()),并返回if not sun_shines(), do: open_umbrella()。所以宏是一个在你的“死代码”级别工作并生成“死代码”的函数。
您可能会认为编写宏太愚蠢了。确实如此。但是这些类型的问题比您想象的更频繁地发生,然后宏是解决该问题的好方法。这只是一种对您的编程语言进行编程的方式。
Aleksei Matiushkin 提供了unless 宏的示例实现:
defmodule MyMacros do
defmacro unless(ast, do: block) do
quote do
if not unquote(ast) do
unquote(block)
end
end
end
end
在这里您可以清楚地看到您给它一个 AST(抽象语法树),它会将其转换为另一个 AST (quote),并将其注入到您调用宏的位置。请注意,这一切都发生在编译时。您的程序此时尚未执行!
例如,假设您有上述模块可用,这是您的程序:
defmodule MyProgram do
def my_function(x) do
unless sun_shining() do
open_umbrella()
end
end
end
编译后执行前,您的程序将如下所示:
defmodule MyProgram do
def my_function(x) do
if not sun_shining() do
open_umbrella()
end
end
end
这个阶段就是我们所说的宏观扩张阶段。
另外,在这里您可以找到分别在 Elixir 和 ExUnit 中使用的两个实际宏。
https://github.com/elixir-lang/elixir/blob/d48b16cf549eca0629449a47cc5574a7170706c3/lib/ex_unit/lib/ex_unit/assertions.ex#L104
https://github.com/elixir-lang/elixir/blob/13ced80fcda1bea69037aacd4b052a0c44b4be61/lib/elixir/lib/stream/reducers.ex#L58
注意:我一直在为这个答案添加越来越多的信息。答案实际上值得一本书,而 Chris McCord 的 Metaprogramming Elixir 是最好的。