I am currently reading Programming Elixir and I am doing one of the exercises where you should write a solution to the “I’m thinking of a number between 1 and 1000”

I have made it work, but I wanted to add a simple guard clause: I want to check if the passed number is actually in the passed range. As far as I have read only handful of functions and operators are allowed in guard clauses, but the ‘in’ is one of them.

So 1st I tried this:

def guess(actual, range) when (actual not in range), do: IO.puts "actual #{actual} is not in #{range}"

But I got: (ArgumentError) invalid args for operator “in”, it expects a compile-time proper list or compile-time range on the right side.

2nd I tried to make a list from the range:

def guess(actual, range) when (actual not in (Enum.to_list range), do: IO.puts "actual #{actual} is not in #{range}

And again I got the same error, this time saying that I the right side is the function itself instead the evaluation of it, which should be proper list ?!?

Guards are very limited, and much of the fancy properties of in in guards is done at compile time using macros; because of this a compile time range literal can be used, but a runtime range value cannot.

Which is quite less readable and you have to remember to do it that way, while using the n in a..b approach just works.

Sounds like a good use for a defguard (especially with OTP21’s new map_get guards as then you could make a in_range/2, but otherwise an in_range/3 would work regardless, though an in-range/2 could be made if my original defguard proposal was made instead…).