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
160
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
720
Protobuf in Elixir
tony612
2
740
The way to grpc-elixir
tony612
2
1.5k
Why I love Elixir
tony612
7
1.3k
GitHub is the new Sexy
tony612
0
110
Other Decks in Programming
See All in Programming
flutter_kaigi_2025.pdf
kyoheig3
1
270
仕様がそのままテストになる!Javaで始める振る舞い駆動開発
ohmori_yusuke
6
3.4k
Kotlin 2.2が切り拓く: コンテキストパラメータで書く関数型DSLと新しい依存管理のかたち
knih
0
420
Amazon Bedrock Knowledge Bases Hands-on
konny0311
0
140
2025 컴포즈 마법사
jisungbin
0
110
Agentに至る道 〜なぜLLMは自動でコードを書けるようになったのか〜
mackee
4
780
FlutterKaigi 2025 システム裏側
yumnumm
0
960
CSC509 Lecture 13
javiergs
PRO
0
250
オンデバイスAIとXcode
ryodeveloper
0
470
Kotlinで実装するCPU/GPU 「協調的」パフォーマンス管理
matuyuhi
0
390
TVerのWeb内製化 - 開発スピードと品質を両立させるまでの道のり
techtver
PRO
1
280
HTTPじゃ遅すぎる! SwitchBotを自作ハブで動かして学ぶBLE通信
occhi
0
240
Featured
See All Featured
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.2k
Site-Speed That Sticks
csswizardry
13
960
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
4 Signs Your Business is Dying
shpigford
186
22k
Building a Scalable Design System with Sketch
lauravandoore
463
33k
Practical Orchestrator
shlominoach
190
11k
How to Think Like a Performance Engineer
csswizardry
28
2.3k
Visualization
eitanlees
150
16k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
Facilitating Awesome Meetings
lara
57
6.6k
Context Engineering - Making Every Token Count
addyosmani
9
380
The Cost Of JavaScript in 2023
addyosmani
55
9.2k
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"