Найти тему
IDE Cat

Макросы в Elixir для маленьких

Оглавление

Данная статья рассчитана на тех, кто уже немного познакомился с метапрограммированием в эликсире, но так и не понял, где же применять и творить магию.

Повторим: quote и unquote

Выражения в эликсире представляют собой кортежи. Эти кортежи состоят из трех частей: название функции, метаданные и аргументы функции.

Например блок указанный ниже вернет список кортежей для каждого выражения, для List.last, для пайплайна и для Enum.sum.

quote — возвращает внутренние структуры выражений

unquote — разворачивает внутри этих структур значения переданных переменных, тем самым позволяя указать в структуре кортежа название нужной функции или значение аргументов. За счет этого в эликсире обеспечивается метапрограммирование.

Рассмотрим несколько примеров, которые помогут лучше понять область применения макросов в эликсире.

Пример №1

Внутри модулей мы часто используем значения из конфига приложения, обычно это делается командой:

Application.get_env(:my_awesome_app, __MODULE__)[:link]

Где :my_awesome_app — ключ otp_app;
__MODULE__ — название модуля;
:link — параметр конфига (ключ).

Эта довольно громоздкая конструкция начинает повторяться в разных модулях, что понижает читаемость кода. Тут нам на помощь приходят макросы.

Объявим на уровне приложения следующий макрос:

-2

Теперь в модулях приложения MyAwesomeApp можно получать значения конфига простой командой:

MyAwesomeApp.get_config(:link)
-3

Функция host вернет значение host из конфига модуля Foo.

-4

Пример №2

Давайте улучшим стандартный Logger, чтобы он сохранял чуть больше информации, чем обычно. Напишем абстракцию, которая дополнит стандартную запись в лог информацией о хосте и функции, из которой мы производим логирование.

Создадим модуль MyLogger

-5

Теперь, когда мы будем пользоваться функцией info нашего Logger’а, в логах будет выводиться дополнительная информация.

-6

Например при вызове Foo.bar в логах будет запись:

23:06:09.800 [info] [host: macbook_2017, fun: bar/1] Actions completed

Пример №3

С помощью метапрограммирования мы можем динамически создавать функции, хоть макросы здесь и не пригодятся.

Напишем модуль, который возвращает целые числа от 1 до 99, где функция будет числовым литералом.

-7

Теперь можем получать цифровые значения всего лишь обратившись к соответствующей функции:

Number.sixty_one # 61
Number.forty_two # 42
Number.one # 1

Надеюсь данная статья помогла лучше освоить макросы и метапрограммирование в эликсире. Если остались какие-то вопросы, буду рад ответить на них в комментариях.