Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Intro to Elixir macro
Search
tony612
May 22, 2017
Programming
2
140
Intro to Elixir macro
keynote at Elixir Meetup 2017.5.21
https://www.meetup.com/Elixir-Shanghai/events/238614338/
tony612
May 22, 2017
Tweet
Share
More Decks by tony612
See All by tony612
My simple reverse proxy in Elixir
tony612
1
690
Protobuf in Elixir
tony612
2
690
The way to grpc-elixir
tony612
2
1.5k
Why I love Elixir
tony612
7
1.3k
GitHub is the new Sexy
tony612
0
100
Other Decks in Programming
See All in Programming
Cursor/Devin全社導入の理想と現実
saitoryc
25
18k
AWS で実現する安全な AI エージェントの作り方 〜 Bedrock Engineer の実装例を添えて 〜 / how-to-build-secure-ai-agents
gawa
8
880
小田原でみんなで一句詠みたいな #phpcon_odawara
stefafafan
0
350
カオスに立ち向かう小規模チームの装備の選択〜フルスタックTSという装備の強み _ 弱み〜/Choosing equipment for a small team facing chaos ~ Strengths and weaknesses of full-stack TS~
bitkey
1
110
AHC045_解説
shun_pi
0
560
エンジニア向けCursor勉強会 @ SmartHR
yukisnow1823
2
7.8k
Deoptimization: How YJIT Speeds Up Ruby by Slowing Down / RubyKaigi 2025
k0kubun
0
1.4k
Memory API : Patterns, Performance et Cas d'Utilisation
josepaumard
1
140
「影響が少ない」を自分の目でみてみる
o0h
PRO
2
1.2k
AI時代の開発者評価について
ayumuu
0
200
大LLM時代にこの先生きのこるには-ITエンジニア編
fumiyakume
7
3.2k
Dissecting and Reconstructing Ruby Syntactic Structures
ydah
2
1.3k
Featured
See All Featured
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
How GitHub (no longer) Works
holman
314
140k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
21k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.4k
Navigating Team Friction
lara
185
15k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
5
570
Build your cross-platform service in a week with App Engine
jlugia
230
18k
Faster Mobile Websites
deanohume
306
31k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
45
7.2k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
47
2.7k
Fireside Chat
paigeccino
37
3.4k
Transcript
*OUSPUP&MJYJSNBDSP !UPOZ
0WFSWJFX ˙ 8IBU’TNBDSP ˙ 8IZNBDSP ˙ )PXJTNBDSPJNQMFNFOUFEJO&MJYJS ˙
)PXUPVTF ˙ 8IFOUPVTF
8IBU’TNBDSP
"NBDSPJTBOPSEJOBSZQJFDFPG-JTQDPEFUIBU PQFSBUFTPOBOPUIFSQJFDFPGQVUBUJWF-JTQ DPEF USBOTMBUJOHJUJOUP BWFSTJPODMPTFSUP FYFDVUBCMF-JTQ .BDSPJO-JTQ IUUQDMDPPLCPPLTPVSDFGPSHFOFUNBDSPTIUNM
"NBDSPJTBOPSEJOBSZQJFDFPG&MJYJSDPEF UIBUPQFSBUFTPOBOPUIFSQJFDFPGRVPUFE&MJYJS DPEF USBOTMBUJOHJUJOUPRVPUFE&MJYJS .BDSPJO&MJYJS
EFGNBDSP defmodule MyLogic do defmacro unless(expr, opts) do quote do
if !unquote(expr), unquote(opts) end end end require MyLogic MyLogic.unless false do IO.puts "It works" end
&MJYJSDPEFUP"45 sum(1, 2, 3) => {:sum, [], [1, 2, 3]}
x => {:x, [], Elixir} %{1 => 2} => {:%{}, [], [{1, 2}]} Foo.run(1, 2) => {{:., [], [{:__aliases__, [alias: false], [:Foo]}, :run]}, [], [1, 2]}
RVPUF quote do defmodule Foo do def foo do 1
end end end {:defmodule, [context: Elixir, import: Kernel], [{:__aliases__, [alias: false], [:Foo]}, [do: {:def, [context: Elixir, import: Kernel], [{:foo, [context: Elixir], Elixir}, [do: 1]]}]]}
.FUBQSPHSBNNJOH XJLJQFEJB ˙ $PNQVUFSQSPHSBNTIBWFUIFBCJMJUZUPUSFBU QSPHSBNTBTUIFJSEBUB ˙ "QSPHSBNDBOCFEFTJHOFEUPSFBE HFOFSBUF BOBMZTFPSUSBOTGPSNPUIFSQSPHSBNT
8IZNBDSP
.FUBQSPHSBNNJOH XJLJQFEJB ˙ .JOJNJ[FUIFBNPVOUPGDPEFUPFYQSFTTB TPMVUJPO BOEUIVTSFEVDJOHUIFEFWFMPQNFOU UJNF ˙ .PWFDPNQVUBUJPOTGSPNSVOUJNFUPDPNQJMF UJNF
˙ (FOFSBUFDPEFVTJOHDPNQJMFUJNF DPNQVUBUJPOT
MFTTDPEF NPSFFFDUJWF defmodule MyRouter do use Plug.Router plug :match #
middleware plug :dispatch # middleware get "/hello" do # logic for a route send_resp(conn, 200, "world") end end
DPNQVUFBUDPNQJMFUJNF # config.yml web_port: 8080 Config.get(:web_port) => 8080 OPUBHPPEFYBNQMF
(FOFSBUFDPEF iex> String.upcase("Elixir Shànghăi") "ELIXIR SHÀNGHĂI" IUUQTHJUIVCDPNFMJYJSMBOHFMJYJSCMPCNBTUFS MJCFMJYJSVOJDPEFVOJDPEFFY-
)PXJTNBDSPJNQMFNFOUFE JO&MJYJS
$PNQJMJOHPG&MJYJS
"OFYBNQMF defmodule Foo do defmacro add1(x) do quote do x
+ 1 end end end Foo.add1(2)
$PEFUP"45 quote do: Foo.add1(2) => { {:., [], [{:__aliases__, [alias:
false], [:Foo]}, :add1]}, [], [2]}
.BDSPFYQBOTJPO require Foo Macro.expand(quote(do: Foo.add1(2)), __ENV__) => {:+, [context: Foo,
import: Kernel], [{:x, [], Foo}, 1]} quote do: Foo.add1(2) => { {:., [], [{:__aliases__, [alias: false], [:Foo]}, :add1]}, [], [2]}
Macro.to_string({:+, [context: Foo, import: Kernel], [{:x, [], Foo}, 1]}) =>
"x + 1" "45UPDPEF
4PPVSDPEFDIBOHFTBGUFSFYQBOTJPO Foo.add1(2) => x + 1
None
)PXUPVTF
5IJOLPGUIFOBMDPEF BGUFSFYQBOTJPO %FOFNBDSPTUPHFOFSBUFUIFDPEF 8SJUFBOESVOVOJUUFTUT PSSVOJOJFY 3FQFBU
&YBNQMFBTJNQMF'4.MJC VTJOH%4-
6TBHFPGUIFMJC defmodule Door do trans :push, "closed", "opened" trans :pull,
"opened", "closed" end state0 = "closed" state1 = Door.push(state0) # "opened" state2 = Door.pull(state1) # "closed"
5IFFYQBOEFEDPEF defmodule Door do def push("closed") do "opened" end def
pull("opened") do "closed" end end
4PXFOFFE 5IFBCJMJUZUPJOKFDUNBDSPUSBOT 6TFUSBOTUPHFOFSBUFGVODUJPOT
IUUQTIFYEPDTQNFMJYJS,FSOFMIUNMVTF VTFUPJOKFDUBNPEVMF
defmodule Door do use FSM trans :push, "closed", "opened" trans
:pull, "opened", "closed" end # expanded => defmodule Door do import FSM.DSL, only: [trans: 3] # ... end
defmodule FSM do defmacro __using__(opts) do quote do import FSM.DSL,
only: [trans: 3] end end end defmodule FSM.DSL do defmacro trans(name, from, to) do # ... end end
*NQMFNFOUUSBOTJO'4.%4- defmacro trans(name, from, to) do quote do def name(from)
do to end end end 5IJTJTXSPOH
(FOFSBUFEDPEFXJMMCF defmodule Door do def name(from) do to end def
name(from) do to end end 5IJTJTXSPOH
VORVPUFUPDPNQVUFFYQSFTTJPO CFGPSFNBDSPFYQBOTJPO defmacro trans(name, from, to) do quote do def
unquote(name)(unquote(from)) do unquote(to) end end end
5IFDPEFDBOCFSVOJOJFY IUUQTHJTUHJUIVCDPN UPOZDDGFCCDBCFB MFGTNFYT
"OBEWBODFEGFBUVSF -JTUBMMFWFOUTPGUIF'4.
defmodule Door do use FSM trans :push, "closed", "opened" trans
:pull, "opened", "closed" end Door.__events__ # => [:push, :pull]
˙ 8FDBOVTFNPEVMFBUUSJCVUFTUPTBWFBMMFWFOUT ˙ #VUNPEVMFBUUSJCVUFTDBO’UCFBDDFTTFEJO SVOUJNF ˙ 4PXFOFFEBGVODUJPOUPTBWFUIFBUUSJCVUFTJOB NPEVMFKVTUCFGPSFDPNQJMJOH DPNQJMFEUP CZUFTDPEF
IUUQTIFYEPDTQNFMJYJS.PEVMFIUNMNPEVMFDPNQJMFDBMMCBDLT
defmodule Door do @before_compile FSM.DSL # ... # expanded def
__events__ do # ... end end
defmodule FSM do defmacro __using__(opts) do quote do @before_compile FSM.DSL
end end end defmodule FSM.DSL do defmacro __before_compile__(env) do quote do def __events__ do # ... end end end end
6TFNPEVMFBUUSJCVUFTUPMJTUFWFOUT defmodule FSM do defmacro __using__(opts) do quote do Module.register_attribute(__MODULE__,
:events, accumulate: true) end end end defmacro trans(name, from, to) do quote do @events unquote(name) # ... end end
BOEEFOF@@FWFOUT@@ CFGPSFDPNQJMJOH defmodule FSM.DSL do defmacro __before_compile__(env) do fields =
Module.get_attribute(env.module, :events) quote do def __events__ do unquote(Enum.reverse(fields)) end end end end
5IFDPEFDBOCFSVOJOJFY IUUQTHJTUHJUIVCDPN UPOZDDGFCCDBCFBMFGTN FYT
8IFOUPVTFNBDSP
˙ 8IFOZPVOFFEUIFCFOFUTPGNBDSPT ˙ 8IFOGVODUJPOTDBO’UTPMWFZPVSQSPCMFNT ˙ 8IFOZPVXSJUFBMJCBOEXBOUUPQSPWJEF “GSJFOEMZ”"1* ˙ .BDSPTTIPVMEPOMZCFVTFEBTBMBTUSFTPSU
IUUQFMJYJSMBOHPSHHFUUJOHTUBSUFENFUBNBDSPTIUNMXSJUFNBDSPTSFTQPOTJCMZ 8SJUFNBDSPTSFTQPOTJCMZBOELFFQZPVS NBDSPEFOJUJPOTTIPSU
IUUQFMJYJSMBOHPSHHFUUJOHTUBSUFENFUBNBDSPTIUNM &YQMJDJUJTCFUUFSUIBOJNQMJDJU$MFBSDPEF JTCFUUFSUIBODPODJTFDPEF
2"