Elixir - Macros

Les macros sont l'une des fonctionnalités les plus avancées et les plus puissantes d'Elixir. Comme pour toutes les fonctionnalités avancées de n'importe quel langage, les macros doivent être utilisées avec parcimonie. Ils permettent d'effectuer de puissantes transformations de code au moment de la compilation. Nous allons maintenant comprendre ce que sont les macros et comment les utiliser en bref.

Citation

Avant de commencer à parler de macros, examinons d'abord les composants internes d'Elixir. Un programme Elixir peut être représenté par ses propres structures de données. Le bloc de construction d'un programme Elixir est un tuple avec trois éléments. Par exemple, l'appel de fonction sum (1, 2, 3) est représenté en interne par -

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

Le premier élément est le nom de la fonction, le second est une liste de mots clés contenant des métadonnées et le troisième est la liste d'arguments. Vous pouvez obtenir ceci comme sortie dans le shell iex si vous écrivez ce qui suit -

quote do: sum(1, 2, 3)

Les opérateurs sont également représentés comme de tels tuples. Les variables sont également représentées à l'aide de ces triplets, sauf que le dernier élément est un atome, au lieu d'une liste. En citant des expressions plus complexes, nous pouvons voir que le code est représenté dans de tels tuples, qui sont souvent imbriqués les uns dans les autres dans une structure ressemblant à un arbre. De nombreuses langues appelleraient de telles représentations unAbstract Syntax Tree (AST). Elixir appelle ces expressions citées.

Fin de citation

Maintenant que nous pouvons récupérer la structure interne de notre code, comment la modifier? Pour injecter un nouveau code ou de nouvelles valeurs, nous utilisonsunquote. Lorsque nous décompressons une expression, elle sera évaluée et injectée dans l'AST. Prenons un exemple (dans iex shell) pour comprendre le concept -

num = 25

quote do: sum(15, num)

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

Lorsque le programme ci-dessus est exécuté, il produit le résultat suivant -

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

Dans l'exemple de l'expression quote, elle n'a pas automatiquement remplacé num par 25. Nous devons décompresser cette variable si nous voulons modifier l'AST.

Macros

Maintenant que nous sommes familiers avec les citations et les décitations, nous pouvons explorer la métaprogrammation dans Elixir à l'aide de macros.

Dans le plus simple des termes, les macros sont des fonctions spéciales conçues pour renvoyer une expression entre guillemets qui sera insérée dans notre code d'application. Imaginez que la macro soit remplacée par l'expression entre guillemets plutôt que appelée comme une fonction. Avec les macros, nous avons tout le nécessaire pour étendre Elixir et ajouter dynamiquement du code à nos applications

Laissez-nous implémenter à moins que comme une macro. Nous commencerons par définir la macro à l'aide dudefmacromacro. N'oubliez pas que notre macro doit renvoyer une expression entre guillemets.

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"

Lorsque le programme ci-dessus est exécuté, il produit le résultat suivant -

False expression

Ce qui se passe ici, c'est que notre code est remplacé par le code cité retourné par la macro sauf . Nous avons décompressé l'expression pour l'évaluer dans le contexte actuel et également décompressé le bloc do pour l'exécuter dans son contexte. Cet exemple nous montre la métaprogrammation à l'aide de macros dans elixir.

Les macros peuvent être utilisées dans des tâches beaucoup plus complexes, mais doivent être utilisées avec parcimonie. En effet, la métaprogrammation en général est considérée comme une mauvaise pratique et ne doit être utilisée que lorsque cela est nécessaire.