Suppose you’ve got the following macro, which generates a function:
defmodule MyMacros do
defmacro my_macro(param_1, param_2, do: body) do
quote do
def my_fun(
unquote(param_1) = evaluated_param_1,
unquote(param_2) = evaluated_param_2
) do
IO.inspect(evaluated_param_1)
IO.inspect(evaluated_param_2)
unquote(body)
end
end
end
end
Now, you can generate a function with it, e.g.:
defmodule MyFunctions do
import MyMacros
def my_fun(param_1, param_2)
my_macro(a, b) do
a + b
end
end
And then I want to generate a function which has a guard, something like this (which doesn’t compile of course):
defmodule MyFunctions do
import MyMacros
def my_fun(param_1, param_2)
my_macro(a, b) when a > 10 do
IO.puts("I'm here!")
end
end
I suspect I should somehow pass the guard similarly as the “do” block is passed through the last arg in keyword list, but I’m not sure how to do this (or whether it’s done differently).
Any hints?
This one requires a few more parenthesis to explain:
def my_fun(a, b) when a > 10 do
…
end
boils down to:
def(my_fun(a, b) when a > 10, do: …)
or in a more LISPy pseudo syntax:
def(when(my_fun(a, b), >(a, 10)), do: …)
The macro here is def/2
and the first argument is the whole function head. You’d essentially need to do the same – make the (a, b)
of my_macro(a, b)
no longer be the parameters of the macro, but of the AST of the function head until the do
. This could for example be my_macro do(a, b) when a > 10 do
.
You can see this often used with macros, which try to mimic syntax like with
(which itself is a special form) e.g. in stream_data
:
check all int1 <- integer(),
int2 <- integer(),
int1 > 0 and int2 > 0,
sum = int1 + int2 do
assert sum > int1
assert sum > int2
end
which is essentially this:
check(all(…), do: …)
2 Likes
Thanks @LostKobrakai, I went with something along these lines:
defmacro my_macro({:when, _, [{:_, _, [param_1, param_2]}, guard]}, do: body) do
quote do
def my_fun(
unquote(param_1) = evaluated_param_1,
unquote(param_2) = evaluated_param_2
) when unquote(guard) do
IO.inspect(evaluated_param_1)
IO.inspect(evaluated_param_2)
unquote(body)
end
end
end
which is used like this:
my_macro _(a, b) when a > 10 do
IO.puts("I'm here!")
a * b
end