Elixir - Macros

As macros são um dos recursos mais avançados e poderosos do Elixir. Como acontece com todos os recursos avançados de qualquer linguagem, as macros devem ser usadas com moderação. Eles tornam possível realizar transformações de código poderosas em tempo de compilação. Agora entenderemos o que são macros e como usá-las resumidamente.

Citar

Antes de começarmos a falar sobre macros, vamos primeiro dar uma olhada nos componentes internos do Elixir. Um programa Elixir pode ser representado por suas próprias estruturas de dados. O bloco de construção de um programa Elixir é uma tupla com três elementos. Por exemplo, a soma da chamada de função (1, 2, 3) é representada internamente como -

{:sum, [], [1, 2, 3]}

O primeiro elemento é o nome da função, o segundo é uma lista de palavras-chave contendo metadados e o terceiro é a lista de argumentos. Você pode obter isso como a saída no shell iex se escrever o seguinte -

quote do: sum(1, 2, 3)

Os operadores também são representados como tuplas. As variáveis ​​também são representadas usando tripletos, exceto que o último elemento é um átomo, em vez de uma lista. Ao citar expressões mais complexas, podemos ver que o código é representado em tais tuplas, que frequentemente estão aninhadas umas dentro das outras em uma estrutura semelhante a uma árvore. Muitas línguas chamariam essas representações deAbstract Syntax Tree (AST). Elixir chama essas expressões citadas.

Entre aspas

Agora que podemos recuperar a estrutura interna de nosso código, como podemos modificá-lo? Para injetar novo código ou valores, usamosunquote. Quando retiramos aspas de uma expressão, ela será avaliada e injetada no AST. Vamos considerar um exemplo (em shell iex) para entender o conceito -

num = 25

quote do: sum(15, num)

quote do: sum(15, unquote(num))

Quando o programa acima é executado, ele produz o seguinte resultado -

{:sum, [], [15, {:num, [], Elixir}]}
{:sum, [], [15, 25]}

No exemplo da expressão de aspas, ela não substituiu automaticamente num por 25. Precisamos retirar aspas esta variável se quisermos modificar o AST.

Macros

Portanto, agora que estamos familiarizados com aspas, podemos explorar a metaprogramação no Elixir usando macros.

No mais simples dos termos, macros são funções especiais projetadas para retornar uma expressão entre aspas que será inserida em nosso código de aplicativo. Imagine a macro sendo substituída pela expressão entre aspas, em vez de ser chamada como uma função. Com macros temos tudo que é necessário para estender o Elixir e adicionar código dinamicamente às nossas aplicações

Vamos implementar a menos como uma macro. Começaremos definindo a macro usando odefmacromacro. Lembre-se de que nossa macro precisa retornar uma expressão entre aspas.

defmodule OurMacro do
   defmacro unless(expr, do: block) do
      quote do
         if !unquote(expr), do: unquote(block)
      end
   end
end

require OurMacro

OurMacro.unless true, do: IO.puts "True Expression"

OurMacro.unless false, do: IO.puts "False expression"

Quando o programa acima é executado, ele produz o seguinte resultado -

False expression

O que está acontecendo aqui é que nosso código está sendo substituído pelo código entre aspas retornado pela macro a menos . Tiramos as aspas da expressão para avaliá-la no contexto atual e também retiramos as aspas do bloco do para executá-la em seu contexto. Este exemplo nos mostra a metaprogramação usando macros no elixir.

As macros podem ser usadas em tarefas muito mais complexas, mas devem ser usadas com moderação. Isso ocorre porque a metaprogramação em geral é considerada uma prática ruim e deve ser usada somente quando necessário.