Макрос
Макросы — это конструкции времени компиляции, которые вызываются с абстрактным синтаксическим деревом (AST) Elixir в качестве входных данных и с расширенным абстрактным синтаксическим деревом Elixir в качестве выходных данных.
Давайте рассмотрим простой пример, который демонстрирует разницу между функциями и макросами:
defmodule Example do
defmacro macro_inspect(value) do
IO.inspect(value)
value
end
def fun_inspect(value) do
IO.inpect(value)
value
end
end
Теперь давайте попробуем:
import Example macro_inspect(1) #=> 1 #=> 1 fun_inspect(1) #=> 1 #=> 1
Пока они ведут себя одинаково, так как мы передаём целое число в качестве аргумента. Но что произойдёт, если мы передадим выражение:
macro_inspect(1 + 2)
#=> {:+, [line: 3], [1, 2]}
#=> 3
fun_inspect(1 + 2)
#=> 3
#=> 3
Макрос получает представление кода, переданного в качестве аргумента, тогда как функция получает результат выполнения кода, переданного в качестве аргумента. Макрос должен возвращать расширенное представление кода. Для получения дополнительной информации см. input/0 и output/0.
Чтобы узнать больше об абстрактном синтаксическом дереве (AST) Elixir и о том, как создавать их программно, см. quote/2.
Пользовательские сигилы
Макросы также часто используются для реализации пользовательских сигилов. Чтобы создать пользовательский сигил, определите функцию с именем sigil_{identifier} , которая принимает два аргумента. Первый аргумент будет строкой, второй — списком символов, содержащим любые модификаторы. Если сигил является строчной буквой (например, sigil_x ), то аргумент строки позволит выполнять интерполяцию. Если сигил является заглавной буквой (например, sigil_X ), то строка не будет интерполироваться.
Допустимые модификаторы включают только строчные и прописные буквы. Другие символы приведут к синтаксической ошибке.
Модуль, содержащий пользовательский сигил, должен быть импортирован перед использованием синтаксиса сигила.
Примеры
defmodule MySigils do
defmacro sigil_x(term, [?r]) do
quote do
unquote(term) |> String.reverse()
end
end
defmacro sigil_x(term, _modifiers) do
term
end
defmacro sigil_X(term, [?r]) do
quote do
unquote(term) |> String.reverse()
end
end
defmacro sigil_X(term, _modifiers) do
term
end
end
import MySigils
~x(with #{"inter" <> "polation"})
#=>"with interpolation"
~x(with #{"inter" <> "polation"})r
#=>"noitalopretni htiw"
~X(without #{"interpolation"})
#=>"without \#{"interpolation"}"
~X(without #{"interpolation"})r
#=>"}\"noitalopretni\"{# tuohtiw" Обзор
Типы
- captured_remote_function()
Захваченная удалённая функция в формате &Mod.fun/arity
- input()
Входные данные макроса
- metadata()
Список ключевых слов метаданных AST.
- output()
Выходные данные макроса
- t()
Абстрактное синтаксическое дерево (AST)
Функции
- camelize(строка)
Преобразует заданную строку в формат CamelCase.
- decompose_call(ast)
Декомпозирует локальный или удалённый вызов на его удалённую часть (если она есть), имя функции и список аргументов.
- escape(выражение, opts \\ [])
Рекурсивно экранирует значение, чтобы его можно было вставить в синтаксическое дерево.
- expand(ast, env)
Принимает узел AST и расширяет его до тех пор, пока он больше не может быть расширен.
- expand_once(ast, env)
Принимает узел AST и расширяет его один раз.
- generate_arguments(количество, контекст)
Генерирует узлы AST для заданного количества переменных аргументов, используя
Macro.var/2.- operator?(имя, арность)
Возвращает
true, если заданное имя и арность являются оператором.- pipe(выражение, call_args, позиция)
Перенаправляет
exprвcall_argsв заданнойposition.- postwalk(ast, fun)
Выполняет обход дерева в порядке постфиксной записи, обходя цитируемые выражения.
- postwalk(ast, acc, fun)
Выполняет обход дерева в порядке постфиксной записи, обходя цитируемые выражения, используя накопитель.
- prewalk(ast, fun)
Выполняет обход дерева в порядке префиксной записи, обходя цитируемые выражения.
- prewalk(ast, acc, fun)
Выполняет обход дерева в порядке префиксной записи, обходя цитируемые выражения, используя накопитель.
- quoted_literal?(термин)
Возвращает
true, если данное цитируемое выражение представляет цитируемую литерал.- special_form?(имя, арность)
Возвращает
true, если данное имя и арность являются специальной формой.- struct!(модуль, env)
Расширяет структуру, заданную
moduleв данномenv.- to_string(дерево, fun \\ fn _ast, string -> string end)
Преобразует заданное выражение AST в строку.
- traverse(ast, acc, pre, post)
Выполняет обход дерева в глубину, используя накопитель.
- underscore(атом)
Преобразует данный атом или бинарник в формат нижнего подчёркивания.
- unescape_string(символы)
Деэкранирует заданные символы.
- unescape_string(символы, карта)
Деэкранирует заданные символы в соответствии с заданной картой.
- unpipe(выражение)
Разбивает выражение конвейера на список.
- update_meta(цитирование, fun)
Применяет заданную функцию к метаданным узла, если они содержатся.
- validate(выражение)
Проверяет, являются ли заданные выражения допустимыми цитируемыми выражениями.
- var(переменная, контекст)
Генерирует узел AST, представляющий переменную, заданную атомами
varиcontext.
Типы
captured_remote_function()
Характеристики
captured_remote_function() :: (... -> any())
Захваченная удалённая функция в формате &Mod.fun/arity
input()
Характеристики
input() ::
input_expr() | {input(), input()} | [input()] | atom() | number() | binary() Входы макроса
metadata()
Характеристики
metadata() :: keyword()
Список ключевых слов метаданных AST.
Метаданные в Elixir AST представляют собой список ключевых слов значений. Любой ключ может быть использован, и разные части компилятора могут использовать разные ключи. Например, AST, полученный макросом, всегда будет включать аннотацию :line, а AST, выводимый quote/2, будет содержать только аннотацию :line, если предоставлен параметр :line.
Следующие ключи метаданных являются общедоступными:
-
:context- Определяет контекст, в котором был сгенерирован AST. Например,quote/2будет включать модуль, вызывающийquote/2, в качестве контекста. Это часто используется для различения обычного кода от кода, сгенерированного макросом илиquote/2. -
:counter- Счётчик переменных, используемый для гигиены переменных. С точки зрения компилятора, каждая переменная идентифицируется комбинацией либоnameиmetadata[:counter], либоnameиcontext. -
:generated- Указывает, считается ли код сгенерированным компилятором. Это означает, что компилятор и инструменты, такие как Dialyzer, могут не выдавать определённые предупреждения. -
:keep- Используетсяquote/2с опциейlocation: :keepдля аннотации файла и номера строки исходного кода. -
:line- Номер строки узла AST.
Следующие ключи метаданных активируются Code.string_to_quoted/2:
-
:closing- содержит метаданные об закрывающей паре, например, о закрывающей скобке в кортеже или в карте, или закрывающей скобке в вызове функции с круглыми скобками. Закрывающая скобка не обозначает конец выражения, если есть метаданные:doи:end(когда:token_metadataравно true). -
:column- номер столбца узла AST (если:columnsравно true). -
:delimiter- содержит открывающую разделитель для сигилов, строк и списков символов в виде строки (например,"{","/","'"и т.п.). -
:format- устанавливается в:keyword, когда атом определён как ключевое слово. -
:do- содержит метаданные о местоположенииdoв вызове функции с блокамиdo/end(если:token_metadataравно true). -
:end- содержит метаданные о местоположенииendв вызове функции с блокамиdo/end(если:token_metadataравно true). -
:end_of_expression- обозначает, когда фактически происходит конец выражения. Доступно для всех выражений, кроме последнего внутри__block__(если:token_metadataравно true).
Следующие ключи метаданных являются закрытыми:
-
:alias- Используется для гигиены псевдонимов. -
:ambiguous_op- Используется для улучшения сообщений об ошибках в компиляторе. -
:import- Используется для гигиены импортов. -
:var- Используется для улучшения сообщений об ошибках при неопределённых переменных.
Не полагайтесь на них, так как они могут измениться или быть полностью удалены в будущих версиях языка. Они часто используются quote/2 и компилятором для обеспечения таких функций, как гигиена, улучшенные сообщения об ошибках и т.д.
Если вы добавляете пользовательские ключи в метаданные AST, убедитесь, что вы добавляете их с именем вашей библиотеки или приложения, чтобы избежать конфликтов с ключами, которые потенциально могут быть добавлены компилятором в будущем.
output()
Характеристики
output() ::
output_expr()
| {output(), output()}
| [output()]
| atom()
| number()
| binary()
| captured_remote_function()
| pid() Выход макроса
t()
Характеристики
t() :: input()
Абстрактное синтаксическое дерево (AST)
Функции
camelize(строка)
Характеристики
camelize(String.t()) :: String.t()
Преобразует заданную строку в формат CamelCase.
Эта функция была разработана для преобразования идентификаторов/токенов языка в CamelCase, поэтому она принадлежит модулю Macro. Не используйте ее как общий механизм для преобразования строк в CamelCase, так как она не поддерживает Unicode или символы, которые не являются допустимыми в идентификаторах Elixir.
Примеры
iex> Macro.camelize("foo_bar")
"FooBar"
Если присутствуют заглавные буквы, они никак не изменяются, как механизм сохранения аббревиатур:
iex> Macro.camelize("API.V1")
"API.V1"
iex> Macro.camelize("API_SPEC")
"API_SPEC" decompose_call(аст)
Характеристики
decompose_call(t()) :: {atom(), [t()]} | {t(), atom(), [t()]} | :error Разбивает локальный или удаленный вызов на его удаленную часть (если предоставлена), имя функции и список аргументов.
Возвращает :error при предоставлении недопустимого синтаксиса вызова.
Примеры
iex> Macro.decompose_call(quote(do: foo))
{:foo, []}
iex> Macro.decompose_call(quote(do: foo()))
{:foo, []}
iex> Macro.decompose_call(quote(do: foo(1, 2, 3)))
{:foo, [1, 2, 3]}
iex> Macro.decompose_call(quote(do: Elixir.M.foo(1, 2, 3)))
{{:__aliases__, [], [:Elixir, :M]}, :foo, [1, 2, 3]}
iex> Macro.decompose_call(quote(do: 42))
:error escape(выражение, опции \\ [])
Характеристики
escape(term(), keyword()) :: t()
Рекурсивно экранирует значение, чтобы его можно было вставить в синтаксическое дерево.
Примеры
iex> Macro.escape(:foo)
:foo
iex> Macro.escape({:a, :b, :c})
{:{}, [], [:a, :b, :c]}
iex> Macro.escape({:unquote, [], [1]}, unquote: true)
1
Параметры
:unquote— если true, эта функция оставляет инструкцииunquote/1иunquote_splicing/1неэкранированными, эффективно убирая кавычки из содержимого при экранировании. Этот параметр полезен только при экранировании AST, которые могут содержать фрагменты в кавычках. По умолчанию false.-
:prune_metadata— если true, удаляет метаданные из экранированных узлов AST. Обратите внимание, что этот параметр изменяет семантику экранированного кода и его следует использовать только при экранировании AST, а не значений. По умолчанию false.Например,
ExUnitхранит AST каждого утверждения, поэтому при неудаче утверждения мы можем показать фрагменты кода пользователям. Без этого параметра каждый раз при компиляции модуля теста мы получаем разный MD5 модуля байт-кода, потому что AST содержит метаданные, такие как счётчики, специфичные для среды компиляции. Удаляя метаданные, мы гарантируем детерминированность модуля и уменьшаем объём данных, которыеExUnitдолжен хранить.
Сравнение с Kernel.SpecialForms.quote/2
Функция escape/2 иногда путают с Kernel.SpecialForms.quote/2, потому что примеры выше ведут себя одинаково с обеими. Ключевое различие лучше всего иллюстрируется, когда значение для экранирования хранится в переменной.
iex> Macro.escape({:a, :b, :c})
{:{}, [], [:a, :b, :c]}
iex> quote do: {:a, :b, :c}
{:{}, [], [:a, :b, :c]}
iex> value = {:a, :b, :c}
iex> Macro.escape(value)
{:{}, [], [:a, :b, :c]}
iex> quote do: value
{:value, [], __MODULE__}
iex> value = {:a, :b, :c}
iex> quote do: unquote(value)
{:a, :b, :c}
escape/2 используется для экранирования значений (либо непосредственно переданных, либо привязанных к переменной), в то время как Kernel.SpecialForms.quote/2 генерирует синтаксические деревья для выражений.
expand(аст, среда)
Получает узел AST и расширяет его до тех пор, пока он больше не может быть расширен.
Обратите внимание, что эта функция не обходит AST, а расширяет только корневой узел.
Эта функция использует expand_once/2 под капотом. Проверьте ее для получения дополнительной информации и примеров.
expand_once(аст, среда)
Получает узел AST и расширяет его один раз.
Расширяются следующие элементы:
- Макросы (локальные или удалённые)
- Псевдонимы расширяются (если возможно) и возвращают атомы
- Макросы среды компиляции (
__CALLER__/0,__DIR__/0,__ENV__/0и__MODULE__/0) - Чтение атрибутов модуля (
@foo)
Если выражение не может быть расширено, оно возвращает само выражение. Эта функция не обходит AST, а расширяет только корневой узел.
expand_once/2 выполняет расширение только один раз. Проверьте expand/2 для выполнения расширения до тех пор, пока узел больше не может быть расширен.
Примеры
В примере ниже у нас есть макрос, который генерирует модуль с функцией name_length, возвращающей длину имени модуля. Значение этой функции будет вычислено во время компиляции, а не во время выполнения.
Рассмотрим реализацию ниже:
defmacro defmodule_with_length(name, do: block) do
length = length(Atom.to_charlist(name))
quote do
defmodule unquote(name) do
def name_length, do: unquote(length)
unquote(block)
end
end
end
При вызове так:
defmodule_with_length My.Module do def other_function, do: ... end
Компиляция завершится ошибкой, потому что My.Module, когда заключено в кавычки, не является атомом, а синтаксическим деревом, как показано ниже:
{:__aliases__, [], [:My, :Module]}
При этом нам нужно расширить узел псевдонима выше до атома, чтобы мы могли получить его длину. Расширение узла не является простым, потому что нам также нужно расширить псевдонимы вызывающего модуля. Например:
alias MyHelpers, as: My defmodule_with_length My.Module do def other_function, do: ... end
Итоговое имя модуля будет MyHelpers.Module, а не My.Module. С Macro.expand/2 такие псевдонимы учитываются. Также расширяются локальные и удалённые макросы. Мы могли бы переписать наш макрос выше, используя эту функцию, как:
defmacro defmodule_with_length(name, do: block) do
expanded = Macro.expand(name, __CALLER__)
length = length(Atom.to_charlist(expanded))
quote do
defmodule unquote(name) do
def name_length, do: unquote(length)
unquote(block)
end
end
end generate_arguments(количество, контекст)
Характеристики
generate_arguments(0, context :: atom()) :: []
generate_arguments(pos_integer(), context) :: [{atom(), [], context}, ...]
when context: atom() Генерирует узлы AST для заданного количества переменных аргументов, используя Macro.var/2.
Примеры
iex> Macro.generate_arguments(2, __MODULE__)
[{:arg1, [], __MODULE__}, {:arg2, [], __MODULE__}] operator?(имя, арность)
Характеристики
operator?(name :: atom(), arity()) :: boolean()
Возвращает true если данное имя и арность являются оператором.
pipe(выражение, аргументы_вызова, позиция)
Характеристики
pipe(t(), t(), integer()) :: t()
Направляет expr в call_args в заданной position.
postwalk(аст, функция)
Характеристики
postwalk(t(), (t() -> t())) :: t()
Выполняет обход синтаксических деревьев, цитируемых выражений, в постфиксном порядке.
postwalk(аст, сумма, функция)
Характеристики
postwalk(t(), any(), (t(), any() -> {t(), any()})) :: {t(), any()} Выполняет обход синтаксических деревьев, цитируемых выражений, в постфиксном порядке, используя накопитель.
prewalk(аст, функция)
Характеристики
prewalk(t(), (t() -> t())) :: t()
Выполняет обход синтаксических деревьев, цитируемых выражений, в префиксном порядке.
prewalk(аст, сумма, функция)
Характеристики
prewalk(t(), any(), (t(), any() -> {t(), any()})) :: {t(), any()} Выполняет обход синтаксических деревьев, цитируемых выражений, в префиксном порядке, используя накопитель.
quoted_literal?(термин)
Характеристики
quoted_literal?(t()) :: boolean()
Возвращает true если данное цитируемое выражение представляет цитируемую литерал.
Атомы, числа и функции всегда являются литералами. Бинарные данные, списки, кортежи, карты и структуры являются литералами только в том случае, если все их термины также являются литералами.
Примеры
iex> Macro.quoted_literal?(quote(do: "foo"))
true
iex> Macro.quoted_literal?(quote(do: {"foo", 1}))
true
iex> Macro.quoted_literal?(quote(do: {"foo", 1, :baz}))
true
iex> Macro.quoted_literal?(quote(do: %{foo: "bar"}))
true
iex> Macro.quoted_literal?(quote(do: %URI{path: "/"}))
true
iex> Macro.quoted_literal?(quote(do: URI.parse("/")))
false
iex> Macro.quoted_literal?(quote(do: {foo, var}))
false special_form?(имя, арность)
Характеристики
special_form?(name :: atom(), arity()) :: boolean()
Возвращает true если данное имя и арность являются специальной формой.
struct!(модуль, среда)
Характеристики
struct!(module, Macro.Env.t()) :: %module{} when module: module() Расширяет структуру, заданную module, в заданной env.
Это полезно, когда структура должна быть расширена во время компиляции, и структура, которая расширяется, может или не может быть скомпилирована. Эта функция даже способна расширять структуры, определённые в модуле, который компилируется.
Будет выброшено исключение CompileError, если структура недоступна.
to_string(дерево, функция \\ fn _аст, строка -> строка end)
Характеристики
to_string(t(), (t(), String.t() -> String.t())) :: String.t()
Преобразует заданное выражение AST в строку.
Указанная fun вызывается для каждого узла в AST с двумя аргументами: AST узла, который печатается, и строковое представление этого же узла. Возвращаемое значение этой функции используется в качестве окончательного строкового представления этого узла AST.
Эта функция отбрасывает всю форматирование исходного кода.
Примеры
iex> Macro.to_string(quote(do: foo.bar(1, 2, 3))) "foo.bar(1, 2, 3)" iex> Macro.to_string(quote(do: 1 + 2), fn ...> 1, _string -> "one" ...> 2, _string -> "two" ...> _ast, string -> string ...> end) "one + two"
traverse(аст, сумма, пре, пост)
Характеристики
traverse(t(), any(), (t(), any() -> {t(), any()}), (t(), any() -> {t(), any()})) ::
{t(), any()} Выполняет обход синтаксических деревьев, цитируемых выражений, в глубину, используя накопитель.
underscore(atom)
Спецификации
underscore(atom() | String.t()) :: String.t()
Преобразует заданный атом или двоичное значение в формат с нижним подчеркиванием.
Если задан атом, предполагается, что это модуль Elixir, поэтому он преобразуется в двоичное значение, а затем обрабатывается.
Эта функция была разработана для форматирования идентификаторов/токенов языка с нижним подчеркиванием, поэтому она принадлежит модулю Macro. Не используйте её как общий механизм для преобразования строк с нижним подчеркиванием, так как она не поддерживает Unicode или символы, не являющиеся допустимыми в идентификаторах Elixir.
Примеры
iex> Macro.underscore("FooBar")
"foo_bar"
iex> Macro.underscore("Foo.Bar")
"foo/bar"
iex> Macro.underscore(Foo.Bar)
"foo/bar"
В общем случае, underscore можно рассматривать как обратное преобразование camelize, однако в некоторых случаях форматирование может быть потеряно:
iex> Macro.underscore("SAPExample")
"sap_example"
iex> Macro.camelize("sap_example")
"SapExample"
iex> Macro.camelize("hello_10")
"Hello10" unescape_string(chars)
Спецификации
unescape_string(String.t()) :: String.t()
Распаковывает заданные символы.
Это поведение распаковки по умолчанию в строках Elixir с одинарными и двойными кавычками. Обратитесь к unescape_string/2 для получения информации о настройке карты экранирования.
В этой настройке Elixir экранирует следующие символы: \0, \a, \b, \d, \e, \f, \n, \r, \s, \t и \v. Байты могут быть заданы как шестнадцатеричные значения через \xNN, а кодовые точки Unicode – через \uNNNN экранирование.
Эта функция обычно используется в реализациях сигилов (таких как ~r, ~s и других), которые получают необработанную, неэкранированную строку.
Примеры
iex> Macro.unescape_string("example\\n")
"example\n"
В примере выше мы передаём строку с \n экранированным значением и возвращаем версию с её распаковкой.
unescape_string(chars, map)
Спецификации
unescape_string(String.t(), (non_neg_integer() -> non_neg_integer() | false)) :: String.t()
Распаковывает заданные символы в соответствии с заданной картой.
Обратитесь к unescape_string/1, если вы хотите использовать ту же карту, что и строки Elixir с одинарными и двойными кавычками.
Карта
Карта должна быть функцией. Функция получает целое число, представляющее кодовую точку символа, который она хочет распаковать. Вот функция отображения по умолчанию, реализованная в Elixir:
def unescape_map(unicode), do: true def unescape_map(hex), do: true def unescape_map(?0), do: ?0 def unescape_map(?a), do: ?\a def unescape_map(?b), do: ?\b def unescape_map(?d), do: ?\d def unescape_map(?e), do: ?\e def unescape_map(?f), do: ?\f def unescape_map(?n), do: ?\n def unescape_map(?r), do: ?\r def unescape_map(?s), do: ?\s def unescape_map(?t), do: ?\t def unescape_map(?v), do: ?\v def unescape_map(e), do: e
Если функция unescape_map/1 возвращает false, символ не экранирован, и обратный слэш сохраняется в строке.
Шестнадцатеричные и кодовые точки Unicode будут экранированы, если функция карты возвращает true для ?x. Кодовые точки Unicode, если функция карты возвращает true для ?u.
Примеры
Использование функции unescape_map/1 , определённой выше, просто:
Macro.unescape_string("example\\n", &unescape_map(&1)) unpipe(expr)
Спецификации
unpipe(t()) :: [t()]
Разбивает выражение конвейера на список.
AST для конвейера (последовательность применений |>) похожа на AST последовательности бинарных операторов или применений функций: выражение верхнего уровня – это самый правый :|> (который выполняется последним), а его левая и правая части – это его аргументы:
quote do: 100 |> div(5) |> div(2)
#=> {:|>, _, [arg1, arg2]}
В примере выше, конвейер |> – это самый правый конвейер; arg1 – это AST для 100 |> div(5), а arg2 – это AST для div(2).
Часто бывает полезно иметь AST для такого конвейера как список применений функций. Эта функция делает именно это:
Macro.unpipe(quote do: 100 |> div(5) |> div(2))
#=> [{100, 0}, {{:div, [], [5]}, 0}, {{:div, [], [2]}, 0}]
Мы получаем список, который непосредственно следует за конвейером: сначала 100, затем div(5) (точнее, его AST), затем div(2). 0 как второй элемент кортежей – это позиция предыдущего элемента в конвейере внутри текущего применения функции: {{:div, [], [5]}, 0} означает, что предыдущий элемент (100) будет вставлен в качестве 0-го (первого) аргумента функции div/2, так что AST для этой функции станет {:div, [], [100, 5]} (div(100, 5)).
update_meta(quoted, fun)
Спецификации
update_meta(t(), (keyword() -> keyword())) :: t()
Применяет заданную функцию к метаданным узла, если они присутствуют.
Это часто полезно при использовании с Macro.prewalk/2 для удаления информации, такой как строки и гигиенические счётчики из выражения для хранения или сравнения.
Примеры
iex> quoted = quote line: 10, do: sample()
{:sample, [line: 10], []}
iex> Macro.update_meta(quoted, &Keyword.delete(&1, :line))
{:sample, [], []} validate(expr)
Спецификации
validate(term()) :: :ok | {:error, term()} Проверяет, являются ли заданные выражения допустимыми выражениями в кавычках.
Проверяет Macro.t/0 для спецификации допустимого выражения в кавычках.
Возвращает :ok если выражение допустимо. В противном случае возвращает кортеж в формате {:error, remainder}, где remainder – недопустимая часть выражения в кавычках.
Примеры
iex> Macro.validate({:two_element, :tuple})
:ok
iex> Macro.validate({:three, :element, :tuple})
{:error, {:three, :element, :tuple}}
iex> Macro.validate([1, 2, 3])
:ok
iex> Macro.validate([1, 2, 3, {4}])
{:error, {4}} var(var, context)
Спецификации
var(var, context) :: {var, [], context} when var: atom(), context: atom() Генерирует узел AST, представляющий переменную, заданную атомами var и context.
Примеры
Для построения переменной требуется контекст. В большинстве случаев для сохранения гигиены контекст должен быть __MODULE__/0:
iex> Macro.var(:foo, __MODULE__)
{:foo, [], __MODULE__}
Однако, если необходимо получить доступ к пользовательской переменной, можно передать nil:
iex> Macro.var(:foo, nil)
{:foo, [], nil}
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.10.4/Macro.html