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
790
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
Contextとはなにか
chiroruxx
1
390
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
4.9k
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
4
1.6k
なぜ型を書くのか? TSKaigi2026で改めて考える #tskaigi_smarthr
kajitack
0
210
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
0
160
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
270
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.7k
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
250
dRuby over BLE
makicamel
2
410
20260623_Loop Engineeringで自分の分身の問い合わせBotを作る
ryugen04
0
130
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
210
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.7k
Featured
See All Featured
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
How Software Deployment tools have changed in the past 20 years
geshan
0
34k
Mobile First: as difficult as doing things right
swwweet
225
10k
Between Models and Reality
mayunak
4
360
Large-scale JavaScript Application Architecture
addyosmani
515
110k
BBQ
matthewcrist
89
10k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
220
Ethics towards AI in product and experience design
skipperchong
2
320
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
460
Odyssey Design
rkendrick25
PRO
2
730
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
310
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"