简体   繁体   中英

Erlang vs Elixir Macros

I have came across some Erlang code which I am trying to convert to Elixir to help me learn both of the languages and understand the differences. Macros and metaprogramming in general is a topic I am still trying to get my head around, so hopefully you will understand my confusion.

The Erlang code

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

% where m_rep is a function already defined.

To me, it seems that in the above code, there is two separate definitions of the p2 macro that map to a private function called m_rep . In Elixir though, it seems that it is only possible to have one pattern matching definition. Is it possible to have different ones in Elixir too?

These are not two definitions. The first line is the macro, the second line is the replacement. The confusing bit is that the macro has the same name as the function for which it is generating clauses. For example when using your macro like this:

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

the above will be expanded to:

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

You can use erlc -P to produce a .P file that will show you the effects of macro expansion on your code. Check out this slightly simpler, compilable example:

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

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

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

Using erlc -P macro.erl you will get the following output to macro.P :

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

-module(macro).

-export([foo/1]).

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

In Elixir you can define multiple function clauses using macros as well. It is more verbose, but I think it is also much clearer. The Elixir equivalent would be:

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

which you can use to define multiple function clauses, just like the erlang counterpart:

defmodule MyModule do
  require MyMacros

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

I can't help myself here. :-) If it's the macros you are after then using LFE (Lisp Flavoured Erlang) gives you much better macro handling than either erlang or elixir. It also is compatible with both.

-define(p2(MAT, REP), 
        p2(w = MAT ++ stm) -> m_rep(0, w, stm, REP))

% where m_rep is a function already defined.

The code above has a number of issues.

There's no such thing as a macro with multiple clauses in Erlang. The above code doesn't define two separate definitions of the p2 macro that map to a private function called m_rep . What it does is it defines a 2-argument macro, which defines a p2 function taking some parameters and calling m_rep . However, the parameter definition of the internal p2 function is incorrect:

  • it tries to use ++ with the second argument not being a list
  • it tries to assign a value to an atom (did you mean a capital W , a variable, instead of a small w , an atom?)
  • it tries the assignment in a place where an assignment is not allowed - in a function head.

Did you try to test for equality ( == instead of = ), not to do an assignment? If so, you have to use a guard.

Moreover, it seems to me you're trying to use w and stm as though they were variables and pass them to m_rep , but they're not! Variables in Erlang have to start with a capital letter. Variables in Elixir, on the other hand, do not. It might be you're confusing concepts from the two similar but still different languages.

My general advice would be to pick one language and learn it well and only later with that knowledge under your belt try a different language. Pick Erlang if you're completely new to programming - it's simpler, there are less things to learn upfront. Pick Elixir if you already know Ruby or are more into immediate marketability of your skills.

Please say more about your intention and I might be able to come up with code expressing it. The above snippet is too ambiguous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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