Eiji
Please help me with macro for generating functions
Hi, I looked about generating functions and found one example. I tried to make it work inside macro, but i don’t know how I can fix it. Here is sample code that I need help with:
defmodule FirstExample do
Enum.each [foo: [{:_arg1, [], nil}], bar: []], fn {func_name, args} ->
def unquote(func_name)(unquote_splicing(args)), do: :ok
end
end
defmodule SecondExample do
defmacro my_macro(name) do
quote do
defmodule unquote(name) do
Enum.each [foo: [{:_arg1, [], nil}], bar: []], fn {func_name, args} ->
def unquote(func_name)(unquote_splicing(args)), do: :ok
end
end
end
end
end
Please explain me:
- How
unquoteworks inFirstExample?
unquoteshould work only inside ofquote, right? - How I could correct
SecondExampleto make it work?
Important: I need these data to be insidedefmodule unquote(name) do ... endand I need to generate whole module)?
I can see thatunquotetries to get data outside ofquote, but i don’t know how I can fix it to make it work like inFirstExample.
Marked As Solved
net
I’m guessing @my_data is set by the block. You can split large quote into two quotes, and use [unquote: false] to disable unquote/1. Consider moving the first quote to a private function in MyLib for better readability and maintainability.
defmodule MyLib do
defmacro my_macro(name, do: block) do
function_generator =
quote unquote: false do
for {name, args} <- Example.parse(@my_data) do
def unquote(name)(unquote_splicing(args)), do: :ok
end
end
quote do
defmodule unquote(name) do
unquote(block)
unquote(function_generator)
end
end
end
end
@gregvaughn Enum.each is fine in this case as def just inserts into an ets table.
Also Liked
mudasobwa
Use Module.create/3 that, as by documentation, “Creates a module with the given name and defined by the given quoted expressions.”
defmodule SecondExample do
defmacro my_macro(name) do
contents =
quote do
Enum.map [foo: [{:_arg1, [], nil}], bar: []], fn {func_name, args} ->
quote do: def unquote(func_name)(unquote_splicing(args)), do: :ok
end
end
quote bind_quoted: [name: name, contents: contents] do
Module.create(name, contents, Macro.Env.location(__ENV__))
end
end
end
defmodule Test do
require SecondExample
def test, do: IO.inspect SecondExample.my_macro(Foo), label: "Module content"
end
Test.test
NobbZ
Appending here is totally fine. If not elixir does it, erlang will optimise it away. It will optimise appending to a singleton list into consing.
Also, there is often no problem with appending to a list once, it does get dangerous when done recursively though.
gregvaughn
I’m no macro expert, but don’t you want to be using Enum.map instead of Enum.each so you can capture the generated AST?
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









