Logo
Книга для начинающих
ВходРегистрация
/
Программирование
/
Курс Elixir
/

Новые возможности

Elixir: Новые возможности

Макросы позволяют добавлять в язык новые команды, как в предыдущем упражнении:

defmodule Solution do
  defmacro my_unless(condition, do: expression) do
    quote do
      if(!unquote(condition), do: unquote(expression))
    end
  end
end

На самом деле, в Elixir все конструкции имеют внутреннее представление, даже функции. Это означает, что с помощью макроса можно сгенерировать функцию:

defmodule Exercise do
  defmacro create_multiplier(fn_name, factor) do
    quote do
      def unquote(fn_name)(value) do
        unquote(factor) * value
      end
    end
  end
end

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

defmodule MyModule do
  require Exercise

  Exercise.create_multiplier(:double, 2)
  Exercise.create_multiplier(:triple, 3)

  def run_example() do
    x = double(2)
    IO.puts("Two times 2 is #{x}")
  end
end

MyModule.double(5)
# => 10
MyModule.triple(3)
# => 9
MyModule.run_example()
# => Two times 2 is 4

Создадим универсальный макрос, который за один вызов создает нужное количество функций:

defmodule Exercise do
  defmacro create_functions(fn_list) do
    Enum.map(fn_list, fn {name, factor} ->
      quote do
        def unquote(:"#{name}_value")(value) do
          unquote(factor) * value
        end
      end
    end)
  end
end

И теперь опробуем макрос в новом модуле:

defmodule Example do
  require Exercise

  Exercise.create_functions([{:double, 2}, {:triple, 3}, {:nullify, 0}])
end

Example.double_value(2)
# => 4
Example.triple_value(2)
# => 6
Example.nullify_value(2)
# => 0

Если нужно создать макрос только внутри модуля, то defmacrop то что нужно. Как и приватные функции, макрос объявленный таким образом, будет доступен только в модуле, где макрос объявлен и только во время компиляции.

Задание

Создайте макрос prohibit_words, генерирующий функцию forbidden?, в который передается список запрещенных слов и проверяется, запрещено ли слово, переданное в функцию forbidden?. Если передано не слово, то функция возвращает false:

defmodule Exercise
  require Solution

  Solution.prohibit_words(["hello", "world", "foo"])
end

Exercise.forbidden?("hello")
# => true
Exercise.forbidden?("test")
# => false
Exercise.forbidden?(1)
# => false
Exercise.forbidden?(%{hello: :world})
# => false

Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект

Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

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

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются
/
Программирование
/
Курс Elixir
/

Новые возможности

Elixir: Новые возможности

Макросы позволяют добавлять в язык новые команды, как в предыдущем упражнении:

defmodule Solution do
  defmacro my_unless(condition, do: expression) do
    quote do
      if(!unquote(condition), do: unquote(expression))
    end
  end
end

На самом деле, в Elixir все конструкции имеют внутреннее представление, даже функции. Это означает, что с помощью макроса можно сгенерировать функцию:

defmodule Exercise do
  defmacro create_multiplier(fn_name, factor) do
    quote do
      def unquote(fn_name)(value) do
        unquote(factor) * value
      end
    end
  end
end

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

defmodule MyModule do
  require Exercise

  Exercise.create_multiplier(:double, 2)
  Exercise.create_multiplier(:triple, 3)

  def run_example() do
    x = double(2)
    IO.puts("Two times 2 is #{x}")
  end
end

MyModule.double(5)
# => 10
MyModule.triple(3)
# => 9
MyModule.run_example()
# => Two times 2 is 4

Создадим универсальный макрос, который за один вызов создает нужное количество функций:

defmodule Exercise do
  defmacro create_functions(fn_list) do
    Enum.map(fn_list, fn {name, factor} ->
      quote do
        def unquote(:"#{name}_value")(value) do
          unquote(factor) * value
        end
      end
    end)
  end
end

И теперь опробуем макрос в новом модуле:

defmodule Example do
  require Exercise

  Exercise.create_functions([{:double, 2}, {:triple, 3}, {:nullify, 0}])
end

Example.double_value(2)
# => 4
Example.triple_value(2)
# => 6
Example.nullify_value(2)
# => 0

Если нужно создать макрос только внутри модуля, то defmacrop то что нужно. Как и приватные функции, макрос объявленный таким образом, будет доступен только в модуле, где макрос объявлен и только во время компиляции.

Задание

Создайте макрос prohibit_words, генерирующий функцию forbidden?, в который передается список запрещенных слов и проверяется, запрещено ли слово, переданное в функцию forbidden?. Если передано не слово, то функция возвращает false:

defmodule Exercise
  require Solution

  Solution.prohibit_words(["hello", "world", "foo"])
end

Exercise.forbidden?("hello")
# => true
Exercise.forbidden?("test")
# => false
Exercise.forbidden?(1)
# => false
Exercise.forbidden?(%{hello: :world})
# => false

Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект

Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

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

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются
← ПредыдущийСледующий →
← ПредыдущийСледующий →
← ПредыдущийСледующий →

Ваше упражнение проверяется по этим тестам

defmodule Test do
  use ExUnit.Case

  defmodule Exercise do
    require Solution

    Solution.prohibit_words(["hello", "world", "foo"])
  end

  test "prohibit_words work" do
    assert Exercise.forbidden?("hello")
    assert Exercise.forbidden?("world")
    assert Exercise.forbidden?("foo")
    refute Exercise.forbidden?("baz")
    refute Exercise.forbidden?(2)
    refute Exercise.forbidden?(%{hello: :world})
  end
end
← ПредыдущийСледующий →

Решение учителя откроется через:

20:00

waiting_clock
← ПредыдущийСледующий →