metaprogramming


Elixir - How can I unquote an array of functions in my macro?


Disclaimer: I know that it's possible to write code in a simpler manner, but you should understand that I post simplified code to SO.
I have a module Simple which uses Included:
defmodule Simple do
use Included,
events: [
[
name: :start,
callback: fn(x) -> x * 2 end
], [
name: :finish,,
callback: fn(x) -> x * 3 ; x end
]
]
end
I want Included module to define a function which takes one param for each item in the list above and return a value. So, I'm doing this:
defmodule Included do
defmacro __using__(opts)
events = Keyword.get(opts, :events)
quote bind_quoted: [events: events] do
events
|> Enum.each(fn(event) ->
def unquote(event[:name])(x) do
x
|> unquote(event[:callback]).()
|> IO.puts
end)
end
end
end
The problem here is that I receive invalid quoted expression: #Function<0.105634730. I tried to implement it another way:
defmodule Included do
defmacro __using__(opts)
events = Keyword.get(opts, :events)
events
|> Enum.each(fn(event) ->
quote bind_quoted: [event: event] do
def unquote(event[:name])(x) do
x
|> event[:callback].()
|> IO.puts
end
end
end)
end
end
But in this case I haven't seen functions defined. (No errors, there is no functions Simple.start/1 and Simple.finish/1 here).
My questions are:
How can I define desired functions?
Why did functions not defined in 2nd approach?
I'm not 100% sure why, but inside the quote in Included.__using__/1, the AST of the function is being converted into an actual function. If you add IO.inspect(events) at the start of the quote, you'll get:
[[name: :start, callback: #Function<0.18558591 in file:c.exs>],
[name: :finish, callback: #Function<1.18558591 in file:c.exs>]]
A workaround I found for this is to escape the :callback in the events.
defmacro __using__(opts) do
events = for event <- opts[:events] do
Keyword.update!(event, :callback, &Macro.escape/1)
end
quote bind_quoted: [events: events] do
...
end
Final code:
defmodule Included do
defmacro __using__(opts) do
events = for event <- opts[:events] do
Keyword.update!(event, :callback, &Macro.escape/1)
end
quote bind_quoted: [events: events] do
events
|> Enum.each(fn(event) ->
def unquote(event[:name])(x) do
x
|> unquote(event[:callback]).()
|> IO.puts
end
end)
end
end
end
defmodule Simple do
use Included,
events: [
[
name: :start,
callback: fn(x) -> x * 2 end
], [
name: :finish,
callback: fn(x) -> x * 3 ; x end
]
]
end
Simple.start 10
Simple.finish 10
Output:
20
10

Related Links

How to define functions based on attribute to elixir?
Remove a const qualifier from a variable in D
Meta-modeling crud FROM/JOIN/WHERE statement fragments for higher-level analysis
Elixir: eval'ing code in module context using Code.eval_quoted/3
What is Declarative Meta-Programming?
Reconsolidate protocols in Elixir 1.2 or higher
Inserting an AST into a quote do end block without unquoting it
Transform quoted elixir code to a code string
Pattern matching benchmarking : Compiletime lookup vs Runtime lookup in D
Meta construction capabilities?
How to manipulate the value of variables based on an array of symbols in Julia?
Multiple #:build macros
Julia automatically generate functions and export them
Dealing with end keyword in macros for array indices
Implementation of AnyMap and runtime overhead of `struct Port(u32);`
Can function application be overriden with Macro in Elixir?

Categories

HOME
assembly
cobalt
merge
sh
devise
3d-reconstruction
x264
title
elasticsearch-5
extjs4.2
distribution
stellar.js
job-scheduling
html5-appcache
smartclient
asciidoctor-pdf
rubymotion
scriptella
ckfinder
froala
onload
handler
angular-translate
panoramas
dst
quickfixj
glib
pop3
navigator
wurfl
modernizr
odroid
metawidget
levenshtein-distance
android-softkeyboard
sharp-snmp
robomongo
reportservice2010
amq
backbone-collections
bbpress
rxtx
testrail
node-request
pytables
omxplayer
qtplugin
jquery-jscrollpane
clipboard.js
lua-telegram-bot
dbamp
findfirst
pushbots
invoke-sqlcmd
toran-proxy
dynatree
mirror
canvg
unix-socket
live555
qscrollarea
windows-embedded-standard
android-usb
visual-studio-express
windows-phone-8-sdk
mbunit
node-blade
pagedown
video-codecs
cascadingdropdown
fb.ui
argouml
floating-point-exceptions
cgimage
node-redis
undefined-index
updatesourcetrigger
pbcopy
mathematical-typesetting

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App