Erlang vs Elixir 宏

Posted

技术标签:

【中文标题】Erlang vs Elixir 宏【英文标题】:Erlang vs Elixir Macros 【发布时间】:2016-05-05 17:53:36 【问题描述】:

我遇到了一些 Erlang 代码,我正在尝试将其转换为 Elixir,以帮助我学习这两种语言并理解它们之间的差异。一般来说,宏和元编程是我仍在努力解决的一个话题,所以希望你能理解我的困惑。

Erlang 代码

-define(p2(MAT, REP), 
        p2(W = MAT ++ STM) -> m_rep(0, W, STM, REP))

% where m_rep is a function already defined.

在我看来,在上面的代码中,p2 宏的两个单独定义映射到一个名为 m_rep 的私​​有函数。但在 Elixir 中,似乎只能有一个模式匹配定义。 Elixir 也可以有不同的吗?

【问题讨论】:

我不知道你是否熟悉 C 和 Lisp,但一个简单的类比是 Erlang 的宏类似于 C 宏(即简单的编译时字符串替换),而 Elixir 的宏类似于 Lisp宏(即可以操作 AST 的代码)。 @OnorioCatenacci 这很有趣!非常感谢你帮助我理解。 :-) 【参考方案1】:

这不是两个定义。第一行是宏,第二行是替换。令人困惑的一点是,宏与为其生成子句的函数同名。例如,当您像这样使用宏时:

?p2("a", "b");
?p2("c", "d").

以上将扩展为:

p2(w = "a" ++ stm) -> m_rep(0, w, stm, "b");
p2(w = "c" ++ stm) -> m_rep(0, w, stm, "d").

您可以使用erlc -P 生成一个.P 文件,该文件将向您展示宏扩展对您的代码的影响。看看这个稍微简单的可编译示例:

-module(macro).
-export([foo/1]).

-define(foo(X),
        foo(X) -> X).

?foo("bar");
?foo("baz");
?foo("qux").

使用erlc -P macro.erl,您将获得以下输出到macro.P

-file("macro.erl", 1).

-module(macro).

-export([foo/1]).

foo("bar") ->
    "bar";
foo("baz") ->
    "baz";
foo("qux") ->
    "qux".

在 Elixir 中,您也可以使用宏定义多个函数子句。它更冗长,但我认为它也更清晰。 Elixir 等价物是:

defmodule MyMacros do
  defmacro p2(mat, rep) do
    quote do
      def p2(w = unquote(mat) ++ stm) do
        m_rep(0, w, stm, unquote(rep))
      end
    end
  end
end

您可以使用它来定义多个函数子句,就像 erlang 对应物一样:

defmodule MyModule do
  require MyMacros

  MyMacros.p2('a', 'b')
  MyMacros.p2('c', 'd')
end

【讨论】:

你在这里教会了我很多东西。谢谢你这么详细的回答。【参考方案2】:
-define(p2(MAT, REP), 
        p2(w = MAT ++ stm) -> m_rep(0, w, stm, REP))

% where m_rep is a function already defined.

上面的代码有很多问题。

在 Erlang 中没有包含多个子句的宏。上面的代码没有定义两个独立的p2 宏定义,它们映射到一个名为m_rep 的私​​有函数。它的作用是定义了一个 2 参数宏,它定义了一个 p2 函数,它接受一些参数并调用 m_rep。但是内部p2函数的参数定义不正确:

它尝试使用++,而第二个参数不是列表 它试图为一个原子赋值(你是说大写的W,一个变量,而不是一个小的w,一个原子?) 它会在不允许赋值的地方尝试赋值 - 在函数头中。

您是否尝试测试是否相等(== 而不是=),而不是做作业?如果是这样,您必须使用警卫。

此外,在我看来,您似乎正在尝试使用 wstm,就好像它们是变量并将它们传递给 m_rep,但它们不是! Erlang 中的变量必须以大写字母开头。另一方面,Elixir 中的变量则不然。您可能会混淆这两种相似但仍然不同的语言的概念。

我的一般建议是选择一种语言并学好它,然后在掌握了这些知识之后再尝试另一种语言。如果您对编程完全陌生,请选择 Erlang - 它更简单,需要预先学习的东西更少。如果您已经了解 Ruby 或更想立即推广您的技能,请选择 Elixir。

请详细说明您的意图,我可能会想出表达它的代码。上面的sn-p太模棱两可了。

【讨论】:

您对变量名的看法是正确的。为混乱道歉!【参考方案3】:

在这里我无法自拔。 :-) 如果它是您所追求的宏,那么使用 LFE (Lisp Flavoured Erlang) 可以为您提供比 erlang 或 elixir 更好的宏处理很多。它也兼容两者。

【讨论】:

以上是关于Erlang vs Elixir 宏的主要内容,如果未能解决你的问题,请参考以下文章

大神来了Elixir语言设计者José Valim:释放Erlang VM的能量

混合 Elixir 和 Erlang?

Erlang - Elixir:啥是监督树?

使用 Erlang 的 Elixir 模块失败

Elixir/Erlang

Elixir/Erlang 并发状态访问