I am trying to create two functions :red_pieces
and :black_pieces
inside the module Board
meant to get an element from the struct.
I want the compiled function to pattern match on %Board
to it would take the argument %Board{red_pieces: pieces}
for example. So this would look like:
def red_pieces(%Board{red_pieces: pieces}, n)
case pieces do
%{^n => b} -> {:ok, b}
_ -> {:nil, :nil}
end
end
Currently I can get it to work without pattern matching and just getting the struct fields in the function body like so:
defmodule Board do
defstruct black_pieces: %{}, red_pieces: %{}
# Creates functions: &Board.red_pieces/2 and &Board.black_pieces/2
for fg <- [:red_pieces, :black_pieces] do
def unquote(fg)(board = %__MODULE__{}, n) do
case board.unquote(fg) do
%{^n => b} -> {:ok, b}
_ -> {:nil, :nil}
end
end
end
end
However, instead of doing b = %__MODULE__{}
and then case b.unquote(fg)
I would like to pattern match on the value of fg
so it would be like %__MODULE{red_pieces: pieces}
, but I can't figure out how to do this.
Obviously, I could just create the two separate functions explicitly, but just for general learning purposes I was wondering if it was possible using metaprogramming.
You could use unquote
on the key like %__MODULE__{unquote(fg) => pieces}
:
for fg <- [:red_pieces, :black_pieces] do
def unquote(fg)(%__MODULE__{unquote(fg) => pieces}, n) do
case pieces do
%{^n => b} -> {:ok, b}
_ -> {nil, nil}
end
end
end
%{black_pieces: pieces}
is just syntactic sugar for %{:black_pieces => pieces}
. You need to desugar it in order to use unquote
, otherwise it won't be valid elixir syntax.