Языковые конструкции против макросов в эликсире - PullRequest
0 голосов
/ 19 марта 2019

Я изучаю управляющие структуры из https://elixirschool.com/en/lessons/basics/control-structures/, и я заметил, что там упоминается

Скорее всего, вы сталкивались с / 2 раньше, и если вы использовали Ruby, то вызнакомы с разве что / 2.В Elixir они работают почти так же, но они определяются как макросы, а не как языковые конструкции.Вы можете найти их реализацию в модуле Kernel.

Так в чем же разница между языковой конструкцией и макросом в Elixir и когда нужно писать макрос?

1 Ответ

3 голосов
/ 19 марта 2019

Макрос - это способ программирования языка программирования.Проще говоря, макрос - это способ генерировать программный код, а не писать его все время.

С другой стороны, языковая конструкция (иногда называемая «особой формой») - это то, что лежит в основе самого эликсира.Упрощение может заключаться в том, что реализация if осуществляется не в Elixir, а на языке, на котором реализован Elixir.

Предположим, вы хотите использовать упомянутое unless.

Редактировать: unless - это , доступный в эликсире.Но давайте предположим, что это не так.

В Elixir нет unless, доступного на языке.Хосе Валим не реализовал это.Но вы всегда можете написать что-то, что имеет ту же семантику: отрицательный if.

Мы бы хотели бы , чтобы иметь это, но мы не :

unless sun_shines() do 
  open_umbrella()
end

Но у нас есть только if и not, поэтому мы можем написать:

if not sun_shines() do 
  open_umbrella()
end

Во-вторых, макрос - это особый вид функции, но его параметрыявляются кодом, и результатом выполнения макроса также является код.Предполагая, что у нас есть макрос unless, он принимает условие (т. Е. sun_shines()) и тело (т. Е. open_umbrella()) и возвращает if not sun_shines(), do: open_umbrella().Таким образом, макрос - это функция, которая работает на уровне вашего «мертвого кода» и генерирует «мертвый код».

Вы можете подумать, что это слишком глупо, чтобы писать макрос для.Это правда.Но такого рода проблемы случаются чаще, чем вы думаете, и тогда макрос является отличным решением этой проблемы.Это просто способ программирования вашего языка программирования.

Пример реализации макроса unless был предоставлен Алексеем Матюшкиным:

defmodule MyMacros do
  defmacro unless(ast, do: block) do
    quote do
      if not unquote(ast) do
        unquote(block)
      end
    end
  end
end

Здесь вы можете ясно видеть, что вы даете ему AST (Абстрактное синтаксическое дерево), и этопреобразует его в другой AST (quote) и вставляет его в то место, где вы вызвали макрос.Обратите внимание, что все это происходит во время компиляции.Ваша программа в данный момент не выполняется!

Например, предположим, что у вас есть вышеуказанный модуль, и это ваша программа:

defmodule MyProgram do 
  def my_function(x) do 
    unless sun_shining() do 
      open_umbrella()
    end
  end
end

После компиляции и перед выполнением вашПрограмма будет выглядеть так:

defmodule MyProgram do 
  def my_function(x) do 
    if not sun_shining() do 
      open_umbrella()
    end
  end
end

Эта фаза называется фазой расширения макроса.

Кроме того, здесь вы можете найти два фактических макроса, используемых в Elixir и ExUnit соответственно.

https://github.com/elixir-lang/elixir/blob/d48b16cf549eca0629449a47cc5574a7170706c3/lib/ex_unit/lib/ex_unit/assertions.ex#L104

https://github.com/elixir-lang/elixir/blob/13ced80fcda1bea69037aacd4b052a0c44b4be61/lib/elixir/lib/stream/reducers.ex#L58

Примечание:Я продолжаю добавлять все больше и больше информации к этому ответу.Ответ на самом деле заслуживает целой книги, и Эликсир метапрограммирования от Крис МакКорд является лучшим.

...