Elixir - Macros
Makra to jedna z najbardziej zaawansowanych i potężnych funkcji Elixiru. Podobnie jak w przypadku wszystkich zaawansowanych funkcji dowolnego języka, makra należy używać oszczędnie. Umożliwiają wykonywanie potężnych przekształceń kodu w czasie kompilacji. Teraz w skrócie zrozumiemy, czym są makra i jak ich używać.
Zacytować
Zanim zaczniemy mówić o makrach, spójrzmy najpierw na wewnętrzne elementy Elixir. Program Elixir może być reprezentowany przez własne struktury danych. Elementem konstrukcyjnym programu Elixir jest krotka z trzema elementami. Na przykład suma wywołań funkcji (1, 2, 3) jest reprezentowana wewnętrznie jako -
{:sum, [], [1, 2, 3]}
Pierwszy element to nazwa funkcji, drugi to lista słów kluczowych zawierająca metadane, a trzeci to lista argumentów. Możesz to otrzymać jako wynik w powłoce iex, jeśli napiszesz:
quote do: sum(1, 2, 3)
Operatory są również reprezentowane jako takie krotki. Zmienne są również reprezentowane za pomocą takich trójek, z tym wyjątkiem, że ostatnim elementem jest atom, a nie lista. Cytując bardziej złożone wyrażenia, widzimy, że kod jest reprezentowany w takich krotkach, które często są zagnieżdżone wewnątrz siebie w strukturze przypominającej drzewo. Wiele języków nazwałoby takie reprezentacjeAbstract Syntax Tree (AST). Elixir nazywa te cytowane wyrażenia.
Zamknąć cudzysłów
Teraz, gdy możemy pobrać wewnętrzną strukturę naszego kodu, jak ją zmodyfikujemy? Aby wstrzyknąć nowy kod lub wartości, używamyunquote. Kiedy usuniemy cytat z wyrażenia, zostanie ono ocenione i wprowadzone do AST. Rozważmy przykład (w powłoce iex), aby zrozumieć pojęcie -
num = 25
quote do: sum(15, num)
quote do: sum(15, unquote(num))
Uruchomienie powyższego programu daje następujący wynik -
{:sum, [], [15, {:num, [], Elixir}]}
{:sum, [], [15, 25]}
W przykładzie wyrażenia quote nie zamieniło automatycznie num na 25. Musimy usunąć cytowanie tej zmiennej, jeśli chcemy zmodyfikować AST.
Makra
Teraz, gdy już znamy cytowanie i niecytowanie, możemy zbadać metaprogramowanie w Elixirze przy użyciu makr.
Mówiąc najprościej, makra to specjalne funkcje przeznaczone do zwracania cytowanego wyrażenia, które zostanie wstawione do kodu naszej aplikacji. Wyobraź sobie, że makro jest zastępowane cytowanym wyrażeniem, a nie nazywane jak funkcja. Dzięki makrom mamy wszystko, co niezbędne do rozszerzenia Elixir i dynamicznego dodawania kodu do naszych aplikacji
Zaimplementujmy chyba jako makro. Zaczniemy od zdefiniowania makra przy użyciudefmacromakro. Pamiętaj, że nasze makro musi zwrócić cytowane wyrażenie.
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"
Uruchomienie powyższego programu daje następujący wynik -
False expression
Co się tu dzieje jest nasz kod jest zastępowany przez cytowanego kodu zwróconego przez chyba makro. Nie zacytowaliśmy wyrażenia, aby ocenić je w bieżącym kontekście, a także nie zacytowaliśmy bloku do, aby wykonać je w jego kontekście. Ten przykład pokazuje nam metaprogramowanie przy użyciu makr w elixirze.
Makra mogą być używane w znacznie bardziej złożonych zadaniach, ale należy ich używać oszczędnie. Dzieje się tak, ponieważ generalnie metaprogramowanie jest uważane za złą praktykę i powinno być używane tylko wtedy, gdy jest to konieczne.