Reputation: 3051
I have the following function, that needs to match only with values of n
being a power of 2 integers (1, 2, 4, 8, 16, 32, 64, ...
):
defmodule MyModule do
def my_func(n) when is_power_of_two(n) do
## Some expression
end
def is_power_of_two(x) do
(x != 0)
and (x &&& (x - 1)) == 0)
end
end
First, I tried defining is_power_of_two
as a function in the module but it didn't work and I got this error:
cannot invoke local is_power_of_two/1 inside guard
.
Following this blog post, I tried to define it as the following macro:
defmodule MyModule.Util do
defmacro is_power_of_two(x) do
quote do
(unquote(x) != 0)
and ((unquote(x) &&& (unquote(x) - 1)) == 0)
end
end
end
Didn't work as well and I get the following error:
cannot invoke local &&&/2 inside guard
It seems that the bitwise &&&
operator cannot be called from a when
clause after the macro expansion.
How to perform matches that requires guards containing bitwise operators?
Upvotes: 1
Views: 562
Reputation: 222158
The error message is misleading. You're just missing an import Bitwise
in MyModule.Util
. The code works if I add the import
:
defmodule MyModule.Util do
import Bitwise
defmacro is_power_of_two(x) do
quote do
(unquote(x) != 0) and ((unquote(x) &&& (unquote(x) - 1)) == 0)
end
end
end
defmodule MyModule do
import MyModule.Util
def my_func(n) when is_power_of_two(n) do
true
end
def my_func(_), do: false
end
IO.inspect MyModule.my_func(128)
IO.inspect MyModule.my_func(129)
Output:
true
false
Upvotes: 4