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
180
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Intro to Elixir macro
keynote at Elixir Meetup 2017.5.21
https://www.meetup.com/Elixir-Shanghai/events/238614338/
tony612
May 22, 2017
More Decks by tony612
See All by tony612
My simple reverse proxy in Elixir
tony612
1
730
Protobuf in Elixir
tony612
2
780
The way to grpc-elixir
tony612
2
1.6k
Why I love Elixir
tony612
7
1.4k
GitHub is the new Sexy
tony612
0
120
Other Decks in Programming
See All in Programming
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
0
180
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
160
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
510
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
200
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
520
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
140
Vite+ Unified Toolchain for the Web
naokihaba
0
140
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
4.7k
These Five Tricks Can Make Your Apps Greener, Cheaper, & Nicer
hollycummins
0
280
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
370
AI駆動開発で崩れていくコードベースを立て直す
kyoko_nr_nr
1
440
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
250
Featured
See All Featured
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Paper Plane
katiecoart
PRO
1
51k
Believing is Seeing
oripsolob
1
140
Un-Boring Meetings
codingconduct
0
310
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.9k
How Software Deployment tools have changed in the past 20 years
geshan
0
34k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
570
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"