ShortMaps
Summary
Macros
Returns a map with the given keys bound to variables with the same name
Macros
Returns a map with the given keys bound to variables with the same name.
This macro sigil is used to reduce boilerplate when writing pattern matches on maps that bind variables with the same name as the map keys. For example, given a map that looks like this:
my_map = %{foo: "foo", bar: "bar", baz: "baz"}
..the following is very common Elixir code:
%{foo: foo, bar: bar, baz: baz} = my_map
foo #=> "foo"
The ~m
sigil provides a shorter way to do exactly this. It splits the given list of words on whitespace (i.e., like the ~w
sigil) and creates a map with these keys as the keys and with variables with the same name as values. Using this sigil, this code can be reduced to just this:
~m(foo bar baz)a = my_map
foo #=> "foo"
~m
can be used in regular pattern matches like the ones in the examples above but also inside function heads:
defmodule Test do
import ShortMaps
def test(~m(foo)a), do: foo
def test(_), do: :no_match
end
Test.test %{foo: "hello world"} #=> "hello world"
Test.test %{bar: "hey there!"} #=> :no_match
Pinning
Matching using the ~m
sigil has full support for the pin operator:
bar = "bar"
~m(foo ^bar) = %{foo: "foo", bar: "bar"} #=> this is ok, `bar` matches
foo #=> "foo"
bar #=> "bar"
~m(foo ^bar) = %{foo: "FOO", bar: "bar"} #=> this is still ok
foo #=> "FOO"; since we didn't pin it, it's now bound to a new value
bar #=> "bar"
~m(foo ^bar) = %{foo: "foo", bar: "BAR"} #=> will raise MatchError
Structs
For using structs instead of plain maps, the first word must be prefixed with '%':
defmodule Foo do
defstruct bar: nil
end
~m(%Foo bar)a = %Foo{bar: 4711}
bar #=> 4711
NOTE: Structs only support atom keys, so you must use the 'a' modifier.
Modifiers
The ~m
sigil supports both maps with atom keys as well as string keys. Atom keys can be specified using the a
modifier, while string keys can be specified with the s
modifier (which is the default).
~m(my_key)s = %{"my_key" => "my value"}
my_key #=> "my value"
Pitfalls
Interpolation isn't supported. ~m(#{foo})
will raise an ArgumentError
exception.
The variables associated with the keys in the map have to exist in the scope if the ~m
sigil is used outside a pattern match:
foo = "foo"
~m(foo bar) #=> ** (RuntimeError) undefined function: bar/0
Discussion
For more information on this sigil and the discussion that lead to it, visit this topic in the Elixir mailing list.