I am trying to build a simple macro to reduce some repetitive code:
defmodule Example do
defguard is_ok(x) when x == :ok or (is_tuple(x) and elem(x, 0) == :ok)
defmacro ok() do
quote do
x when is_ok(x)
end
end
end
which could be used like this:
iex> require Example
iex> import Example
iex> # so far, so good...
iex> res = case {:ok, "Test"} do
ok() -> "Yay!"
_ -> "Failure"
(or also in a with
-ladder, where it is arguably more useful).
However, instead of res
becoming "Yay!"
, the following error is thrown:
** (CompileError) nofile:1: undefined function when/2
(example) expanding macro: Example.ok/0
I have not been able to figure out what is going wrong here. I know for a fact that the guard is_ok
is correct (you can test it yourself). Writing x when is_ok(x)
the long-hand in the case
-statement also works as intended.
It seems like it is a problem with the way the macro is expanded, but where it is going wrong, I cannot figure out.
EDIT: Even stranger, when writing a separate module to use it:
defmodule Bar do
require Example
import Example
def foo(x) do
case x do
ok() -> "Yay"
_ -> "Fail"
end
end
end
and attempting to compile the project, the following compilation error is thrown:
== Compilation error in file lib/bar.ex ==
** (CompileError) lib/bar.ex:6: cannot find or invoke local when/2 inside match. Only macros can be invoked in a match and they must be defined before their invocation. Called as: x when is_ok(x)
expanding macro: Example.ok/0
lib/bar.ex:6: Bar.foo/1
(elixir) lib/kernel/parallel_compiler.ex:208: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
Help is greatly appreciated !