Intro to Elixir macro

Intro to Elixir macro

Dc717fb8a7638b9e5513ecc0b82a1b5b?s=128

tony612

May 22, 2017
Tweet

Transcript

  1. *OUSPUP&MJYJSNBDSP !UPOZ

  2. 0WFSWJFX ˙ 8IBU’TNBDSP  ˙ 8IZNBDSP ˙ )PXJTNBDSPJNQMFNFOUFEJO&MJYJS  ˙

    )PXUPVTF  ˙ 8IFOUPVTF
  3. 8IBU’TNBDSP

  4. "NBDSPJTBOPSEJOBSZQJFDFPG-JTQDPEFUIBU PQFSBUFTPOBOPUIFSQJFDFPGQVUBUJWF-JTQ DPEF USBOTMBUJOHJUJOUP BWFSTJPODMPTFSUP  FYFDVUBCMF-JTQ .BDSPJO-JTQ IUUQDMDPPLCPPLTPVSDFGPSHFOFUNBDSPTIUNM

  5. "NBDSPJTBOPSEJOBSZQJFDFPG&MJYJSDPEF UIBUPQFSBUFTPOBOPUIFSQJFDFPGRVPUFE&MJYJS DPEF USBOTMBUJOHJUJOUPRVPUFE&MJYJS .BDSPJO&MJYJS

  6. 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
  7. &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]}
  8. 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]]}]]}
  9. .FUBQSPHSBNNJOH XJLJQFEJB ˙ $PNQVUFSQSPHSBNTIBWFUIFBCJMJUZUPUSFBU QSPHSBNTBTUIFJSEBUB ˙ "QSPHSBNDBOCFEFTJHOFEUPSFBE HFOFSBUF  BOBMZTFPSUSBOTGPSNPUIFSQSPHSBNT

  10. 8IZNBDSP

  11. .FUBQSPHSBNNJOH XJLJQFEJB ˙ .JOJNJ[FUIFBNPVOUPGDPEFUPFYQSFTTB TPMVUJPO BOEUIVTSFEVDJOHUIFEFWFMPQNFOU UJNF ˙ .PWFDPNQVUBUJPOTGSPNSVOUJNFUPDPNQJMF UJNF

    ˙ (FOFSBUFDPEFVTJOHDPNQJMFUJNF DPNQVUBUJPOT
  12. MFTTDPEF NPSFFFDUJWF 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
  13. DPNQVUFBUDPNQJMFUJNF # config.yml web_port: 8080 Config.get(:web_port) => 8080 OPUBHPPEFYBNQMF

  14. (FOFSBUFDPEF iex> String.upcase("Elixir Shànghăi") "ELIXIR SHÀNGHĂI" IUUQTHJUIVCDPNFMJYJSMBOHFMJYJSCMPCNBTUFS MJCFMJYJSVOJDPEFVOJDPEFFY-

  15. )PXJTNBDSPJNQMFNFOUFE JO&MJYJS

  16. $PNQJMJOHPG&MJYJS

  17. "OFYBNQMF defmodule Foo do defmacro add1(x) do quote do x

    + 1 end end end Foo.add1(2)
  18. $PEFUP"45 quote do: Foo.add1(2) => { {:., [], [{:__aliases__, [alias:

    false], [:Foo]}, :add1]}, [], [2]}
  19. .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]}
  20. Macro.to_string({:+, [context: Foo, import: Kernel], [{:x, [], Foo}, 1]}) =>

    "x + 1" "45UPDPEF
  21. 4PPVSDPEFDIBOHFTBGUFSFYQBOTJPO Foo.add1(2) => x + 1

  22. None
  23. )PXUPVTF

  24. 5IJOLPGUIFOBMDPEF BGUFSFYQBOTJPO  %FOFNBDSPTUPHFOFSBUFUIFDPEF 8SJUFBOESVOVOJUUFTUT PSSVOJOJFY   3FQFBU

  25. &YBNQMFBTJNQMF'4.MJC VTJOH%4-

  26. 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"
  27. 5IFFYQBOEFEDPEF defmodule Door do def push("closed") do "opened" end def

    pull("opened") do "closed" end end
  28. 4PXFOFFE  5IFBCJMJUZUPJOKFDUNBDSPUSBOT  6TFUSBOTUPHFOFSBUFGVODUJPOT

  29. IUUQTIFYEPDTQNFMJYJS,FSOFMIUNMVTF VTFUPJOKFDUBNPEVMF

  30. 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
  31. 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
  32. *NQMFNFOUUSBOTJO'4.%4- defmacro trans(name, from, to) do quote do def name(from)

    do to end end end 5IJTJTXSPOH
  33. (FOFSBUFEDPEFXJMMCF defmodule Door do def name(from) do to end def

    name(from) do to end end 5IJTJTXSPOH
  34. VORVPUFUPDPNQVUFFYQSFTTJPO CFGPSFNBDSPFYQBOTJPO defmacro trans(name, from, to) do quote do def

    unquote(name)(unquote(from)) do unquote(to) end end end
  35. 5IFDPEFDBOCFSVOJOJFY IUUQTHJTUHJUIVCDPN UPOZDDGFCCDBCFB MFGTNFYT

  36. "OBEWBODFEGFBUVSF -JTUBMMFWFOUTPGUIF'4.

  37. defmodule Door do use FSM trans :push, "closed", "opened" trans

    :pull, "opened", "closed" end Door.__events__ # => [:push, :pull]
  38. ˙ 8FDBOVTFNPEVMFBUUSJCVUFTUPTBWFBMMFWFOUT ˙ #VUNPEVMFBUUSJCVUFTDBO’UCFBDDFTTFEJO SVOUJNF ˙ 4PXFOFFEBGVODUJPOUPTBWFUIFBUUSJCVUFTJOB NPEVMFKVTUCFGPSFDPNQJMJOH DPNQJMFEUP CZUFTDPEF

  39. IUUQTIFYEPDTQNFMJYJS.PEVMFIUNMNPEVMFDPNQJMFDBMMCBDLT

  40. defmodule Door do @before_compile FSM.DSL # ... # expanded def

    __events__ do # ... end end
  41. 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
  42. 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
  43. BOEEFOF@@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
  44. 5IFDPEFDBOCFSVOJOJFY IUUQTHJTUHJUIVCDPN UPOZDDGFCCDBCFBMFGTN FYT

  45. 8IFOUPVTFNBDSP

  46. ˙ 8IFOZPVOFFEUIFCFOFUTPGNBDSPT ˙ 8IFOGVODUJPOTDBO’UTPMWFZPVSQSPCMFNT ˙ 8IFOZPVXSJUFBMJCBOEXBOUUPQSPWJEF “GSJFOEMZ”"1* ˙ .BDSPTTIPVMEPOMZCFVTFEBTBMBTUSFTPSU

  47. IUUQFMJYJSMBOHPSHHFUUJOHTUBSUFENFUBNBDSPTIUNMXSJUFNBDSPTSFTQPOTJCMZ 8SJUFNBDSPTSFTQPOTJCMZBOELFFQZPVS NBDSPEFOJUJPOTTIPSU

  48. IUUQFMJYJSMBOHPSHHFUUJOHTUBSUFENFUBNBDSPTIUNM &YQMJDJUJTCFUUFSUIBOJNQMJDJU$MFBSDPEF JTCFUUFSUIBODPODJTFDPEF

  49. 2"