Enum.map inside quote block

244 views
Skip to first unread message

zak9...@gmail.com

unread,
Mar 7, 2015, 2:19:06 PM3/7/15
to elixir-l...@googlegroups.com

The code below is taken from "introducing Elixir" book and it works well. However, if the code in the defmacro is modified such that Enum.map is inside the quote block then the code stops working.


defmodule Functionmaker do
   # This code works
   defmacro create_functions do
       Enum.map planemo_list, fn {name, gravity} ->
           quote do
              def unquote(:"#{name_drop}")(distance) do
                 :math.sqrt(2 * unquote(gravity) * distance)
              end
           end
        end
   end
end

defmodule Drop do
   require FunctionMaker
 
   FunctionMaker.create_functions([{:mercury, 3.7}, {:venus, 8.9},
        {:earth, 9.8}, {:moon, 1.6}, {:mars, 3.7}, {:jupiter, 23.1},
        {:saturn, 9.0}, {:uranus, 8.7}, {:neptune, 11.0}])
end


The code below does not work once Enum.map is moved inside quote block:

   # This code does not work
   defmacro create_functions do
        quote do
            Enum.map unquote(planemo_list), fn {name, gravity} ->
              def unquote(:"#{name_drop}")(distance) do
                 :math.sqrt(2 * unquote(gravity) * distance)
              end
           end
        end
   end



What's wrong?

- Thanks


Saša Jurić

unread,
Mar 7, 2015, 5:45:45 PM3/7/15
to elixir-l...@googlegroups.com
I had to hack my way a bit to get this working (e.g. I think macro should accept planemo_list as a parameter,  and you're using name_drop, when I think it should be name).

With those errors resolved, I got to what I think is your root problem. The solution would be something like:

defmodule Foo do
  defmacro create_functions(planemo_list) do
    quote bind_quoted: [planemo_list: Macro.escape(planemo_list, unquote: true)] do
      Enum.map(planemo_list, ...
      ...

I bolded the differences, the rest of the code should be the same. With this (and changes noted in my first sentence), I got the example working locally.

The problem is that in your non-working code, when you call def unquote(...), you're escaping the outermost quote, and name_drop (which should be name anyway) is resolved from the macro context where that variable doesn't exist.
I blogged about this situation in the last part of my macro series: http://www.theerlangelist.com/2014/07/understanding-elixir-macros-part-6.html
It's a pretty dense article, but hopefully illustrates the problem.

zak9...@gmail.com

unread,
Mar 8, 2015, 5:34:57 AM3/8/15
to elixir-l...@googlegroups.com
Thanks Sasa Juric for your clarifications. Your solution works well and should be integrated into the next edition of "introducing elixir" book.
Regarding name, it should be unquote("#{name}_drop") and not unquote("#{name_drop}") 


On Saturday, March 7, 2015 at 8:19:06 PM UTC+1, zak9...@gmail.com wrote:

Saša Jurić

unread,
Mar 8, 2015, 6:15:22 AM3/8/15
to elixir-l...@googlegroups.com
Glad it works! If you want to dive deeper into macros, I also suggest reading Metaprogramming Elixir by Chris.


--
You received this message because you are subscribed to a topic in the Google Groups "elixir-lang-talk" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elixir-lang-talk/ACPr-4TV7oU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/fb17bf8b-9b3b-418b-8224-556dbd2c1e50%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages