Eiji

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:

  1. How unquote works in FirstExample?
    unquote should work only inside of quote, right?
  2. How I could correct SecondExample to make it work?
    Important: I need these data to be inside defmodule unquote(name) do ... end and I need to generate whole module)?
    I can see that unquote tries to get data outside of quote, but i don’t know how I can fix it to make it work like in FirstExample.

Marked As Solved

net

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

mudasobwa

Creator of Cure

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

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

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?

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement