На самом деле вы можете сделать вид рекурсии, но смысл в том, чтобы подумать о том, что вы делаете, чтобы избежать вызова макроса внутри quote do [....] end
. Ваш пример с IO.puts будет выглядеть примерно так:
defmodule RecMac do
defmacro test_rec(list) do
{:__block__, [], quote_value(list)}
end
defp quote_value([]), do: []
defp quote_value([h | t]) do
if h < 1 do
[]
else
ast = quote do
IO.puts("#{unquote(h)}")
end
[ast | quote_value(t)]
end
end
end
вы заметите две вещи: я использую рекурсию в макросе, но вне кавычек, используя приватную функцию quote_value/1
, и эта функция имеет logi c, который «останавливается» после того, как находит значение ниже 1
. Все «кавычки» помещаются в список, и хитрость заключается в том, чтобы поместить этот список в кортеж {:__block__, [], put_quote_list_here}
Теперь обратите внимание, что этот макрос не будет компилироваться, если параметр списка test_re c не известен заранее (во время компиляции) , поэтому вам нужно вызвать макрос test_rec(["a", "b", 0, 100, 200])
, чтобы компилятор знал размер и элементы этого списка.
Кстати, я использовал рекурсию, оптимизированную для тела, но вы можете легко добавить аккумулятор и преобразовать ее в рекурсию, оптимизированную для хвоста.