# Erlang/OTP 24, Elixir 1.12.3
bmp_signature = <<66, 77>>
#=> "BM"
<<^bmp_signature, _::binary>> = <<66, 77, 30, 0>>
#=> ** (MatchError) no match of right hand side value: <<66, 77, 30, 0>>
Why is this happening?
In short, I'd like to pattern match bitstrings in a cycle, rather than writing method definitions by hand. So instead of this:
@bmp_signature <<66, 77>>
…
def type(<<@bmp_signature, _::binary>>), do: :bmp
…
…something like this:
@signatures %{
"bmp" => <<66, 77>>,
…
}
def detect_type(file) do
find_value_func = fn {extension, signature} ->
case file do
<<^signature, _::binary>> -> extension
_ -> false
end
end
Enum.find_value(@signatures, find_value_func)
end
Is this solvable without metaprogramming?
Your syntax is slightly off. Remember that the pin operator
^pins only a single value. In your example, you were trying to pin it to 2 values.So if the thing you are trying to match on is a binary with 2 values that you are aware of, then you would need to pin both of them, e.g.
The binary syntax
<<>>isn't the only way to do this -- you can accomplish the same with regular strings (assuming the values are in fact strings):The rub here is that you can't pin a prefix because you need a literal value in order to do the match. This is because the length of the binary isn't known beforehand.
If you know your "signatures" always have 2, 3, or 4 characters, you can code your variables to be pinned appropriately. However, if you must deal with a an unknown length, then you'd probably need to rely on something more like a regular expression or
String.starts_with?/2or similar.