简体   繁体   English

灵丹妙药中的语言构造与宏

[英]Language constructs vs Macros in elixir

I'm learning control structures from https://elixirschool.com/en/lessons/basics/control-structures/ and I noticed that it mentions 我正在从https://elixirschool.com/en/lessons/basics/control-structures/学习控制结构,我注意到它提到了

Chances are you've encountered if/2 before, and if you've used Ruby you're familiar with unless/2. 如果您以前遇到过if / 2,并且如果您使用过Ruby,那么您很可能会熟悉,除非/ 2。 In Elixir they work much the same way but they are defined as macros, not language constructs. 在Elixir中,它们的工作方式大致相同,但它们被定义为宏,而不是语言构造。 You can find their implementation in the Kernel module. 您可以在内核模块中找到它们的实现。

so what's the difference between a language construct and a macro in Elixir and when is it necessary to write a macro? 那么Elixir中的语言构造和宏之间有什么区别,何时需要编写宏?

A macro is a way to program a programming language. 宏是一种对编程语言进行编程的方法。 Simply put, a macro is a way to generate program code, instead of writing it yourself all the time. 简而言之,宏是一种生成程序代码的方法,而不是始终自己编写代码。

A language construct on the other hand (sometimes called "special form"), is something that is at the core of elixir itself. 另一方面,语言构造(有时称为“特殊形式”)是长生不老药本身的核心。 An oversimplification could be that the implementation of if is not done in Elixir, but in the language in which Elixir is implemented. 过于简单的做法可能是, if的实现不是在Elixir中完成,而是在实现Elixir的语言中完成。

Suppose you want to use the mentioned unless . 假设您要使用提及的, unless

Edit: unless is available in Elixir. 编辑: unless 提供药剂。 But let's assume for the remainder that it is not. 但是让我们假设其余的不是。

In Elixir, there is no unless available in the language. 在Elixir中, unless有该语言的版本, unless没有其他内容。 José Valim did not implement it. Jose Valim没有实现它。 But you can always write something that has the same semantics: a negated if . 但是,您始终可以编写具有相同语义的内容:否定的if

We would like to have this, but we don't : 我们希望有这一点,但我们不这样做

unless sun_shines() do 
  open_umbrella()
end

But we only have an if and a not , so we can write: 但是我们只有一个if和一个not ,所以我们可以这样写:

if not sun_shines() do 
  open_umbrella()
end

Secondly, a macro is a special kind of function, but its parameters are code, and the result of executing a macro is code as well. 其次,宏是一种特殊的函数,但是其参数是代码,执行宏的结果也是代码。 Assuming we have the unless macro, it takes in a condition (ie, sun_shines() ), and a body (ie, open_umbrella() ), and returns if not sun_shines(), do: open_umbrella() . 假设我们有unless宏,它接受一个条件(即sun_shines()和主体(即open_umbrella()并返回if not sun_shines(), do: open_umbrella() So a macro is a function that works at the level of your "dead code" and generates "dead code". 因此,宏是在“死代码”级别工作并生成“死代码”的函数。

You might think that this is just too stupid to write a macro for. 您可能会认为这太愚蠢,无法为其编写宏。 That's true. 确实如此。 But these types of problems happen more often than you think, and then a macro is a great solution to that problem. 但是这些类型的问题比您想象的要经常发生,因此宏是解决该问题的好方法。 It's just a way to program your programming language. 这只是编程您的编程语言的一种方法。

An example implementation of the unless macro has been provided by Aleksei Matiushkin: 的一个例子实施unless宏已经提供由阿列克谢Matiushkin:

defmodule MyMacros do
  defmacro unless(ast, do: block) do
    quote do
      if not unquote(ast) do
        unquote(block)
      end
    end
  end
end

Here you can clearly see that you give it an AST (Abstract Syntax Tree), and it will transform it to another AST ( quote ), and inject that in the place where you called the macro. 在这里,您可以清楚地看到给它一个AST(抽象语法树),它将把它转换为另一个AST( quote ),并将其注入到您调用宏的位置。 Note that this all happens at compile time. 请注意,这都是在编译时发生的。 Your program is not being executed at this point! 您的程序目前尚未执行!

For example, suppose you have the above module available, and this is your program: 例如,假设您具有上述模块,这是您的程序:

defmodule MyProgram do 
  def my_function(x) do 
    unless sun_shining() do 
      open_umbrella()
    end
  end
end

After compilation, and before execution, your program will look like this: 编译之后,执行之前,您的程序将如下所示:

defmodule MyProgram do 
  def my_function(x) do 
    if not sun_shining() do 
      open_umbrella()
    end
  end
end

This phase is what we call macro expansion phase. 这个阶段称为宏扩展阶段。

As an extra, here you can find two actual macros used in Elixir and ExUnit respectively. 另外,您可以在此处找到分别在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/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 https://github.com/elixir-lang/elixir/blob/13ced80fcda1bea69037aacd4b052a0c44b4be61/lib/elixir/lib/stream/reducers.ex#L58

Note: I keep adding more and more information to this answer. 注意:我一直在为该答案添加越来越多的信息。 The answer actually deserves a whole book and Metaprogramming Elixir by Chris McCord is the best one. 答案实际上是一整本书, 克里斯·麦考德Chris McCord )撰写的Metaprogramming Elixir是最好的一本书。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM