2015-02-03 5 views
8

Ruby имеет открытые классы, которые очень удобны (хотя и оскорблены некоторыми), а Elixir сильно заимствует Ruby, поэтому я ожидал, что Elixir позволит мне снова открыть модуль и добавить к нему макросы после его закрытия, но это не помогло работайте так, как я пробовал. Есть ли способ сделать это? Эта функция доступна еще в Elixir?Открытые модули в Эликсире?

Чтобы сделать этот бетон, давайте возьмем пример из Криса МакКорд в Метапрограммирование эликсир:

defmodule Math do 
    defmacro say({:+, _, [lhs, rhs]}) do 
    quote do 
     lhs = unquote(lhs) 
     rhs = unquote(rhs) 
     result = lhs + rhs 
     IO.puts "#{lhs} plus #{rhs} is #{result}" 
     result 
    end 
    end 

    defmacro say({:*, _, [lhs, rhs]}) do 
    quote do 
     lhs = unquote(lhs) 
     rhs = unquote(rhs) 
     result = lhs * rhs 
     IO.puts "#{lhs} times #{rhs} is #{result}" 
     result 
    end 
    end 
end 

Если я затем добавить макрос для вычитания

defmodule Math do 
    defmacro say({:-, _, [lhs, rhs]}) do 
    quote do 
     lhs = unquote(lhs) 
     rhs = unquote(rhs) 
     result = lhs - rhs 
     IO.puts "#{lhs} minus #{rhs} is #{result}" 
     result 
    end 
    end 
end 

я получаю предупреждение, что я Переосмысление модуль Math, и изначально определенные макросы терпят неудачу. Поэтому очевидно, что мой подход не является правильным, но есть ли другой подход, который может достичь той же цели?

+0

Не следует путать понятие класса с модулем. Хотя они имеют некоторое сходство, они далеки от того же. Например, в модуле Elixir нет таких данных, как личные данные. –

+1

Кстати, ваш пример действительно не использует возможности макросов. Рекомендуется по возможности использовать функции, которые могут быть легко выполнены здесь. Просто используйте 'def' вместо' defmacro' и удалите все 'quote' и 'unquote'. –

+0

Да, правда, но я надеюсь, вы понимаете, что это не совсем мой пример, это Крис МакКорд, и это «тривиальный» пример, просто используемый для демонстрационных целей. Тем не менее, ваш вопрос хорошо принят. – iconoclast

ответ

17

Вы не можете повторно открыть модуль. Поскольку Elixir является скомпилированным языком, путь от исходного кода к исполняемому представлению является односторонним. Механизмы, которые изменяют код, например макросы, оцениваются во время компиляции. Тем не менее, Elixir позволяет вам делать горячую замену кода, т.е. е. вы можете заменить скомпилированный модуль во время выполнения.

Я думаю, что это имеет некоторые интересные последствия. Вы получаете возможность изменять программу во время выполнения - на практике вы контролируете исходный код и поэтому можете менять отдельные части модуля, не меняя других. Тем не менее, мне нравится идея иметь все в одном месте. В Elixir, когда вы смотрите на модуль, вы точно знаете, что у вас есть *.

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


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

+2

Поскольку вы упомянули протоколы, стоит добавить, что местами были бы плагины для обезьян в Ruby для добавления расширений, которые можно было бы точно решить с помощью протоколов. Документация для defprotocol упоминает, например, протокол Blank. Более глубокое сравнение можно найти здесь: http://blog.plataformatec.com.br/2014/06/comparing-protocols-and-extensions-in-swift-and-elixir/ –

+0

Я понимаю протоколы, но я не могу как это может быть применено к проблеме в исходном вопросе. Он все равно не позволит вам добавить именованную функцию в метод, или я ошибаюсь? –

+0

Patrick, вы не можете расширить существующий модуль, но протоколы являются механизмом расширения, так как он позволяет любому разработчику реализовать предопределенное поведение для любого типа данных. Я согласен, хотя это тонкая линия, чтобы идти дальше, и чтобы ваш ответ был более полным, учитывая пример в вопросе! –

Смежные вопросы