Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elixir 黒魔術入門

Elixir 黒魔術入門

Erlang & Elixir Fest 2019 LT 資料

Avatar for tamanugi

tamanugi

May 30, 2019
Tweet

More Decks by tamanugi

Other Decks in Technology

Transcript

  1. summon = fn -> defmodule Tamanugi do def say(), do:

    IO.puts("転生したらモジュールだった件") end end summon.() Tamanugi.say() # → 転生したらモジュールだった件
  2. summon = fn -> defmodule Tamanugi do def say(), do:

    IO.puts("転生したらモジュールだった件") end end summon.() Tamanugi.say() # → 転生したらモジュールだった件 ͂ defmoduleの正体は実はマクロ 匿名関数内であってもdefmoduleが実行されれば モジュールが召喚される mix compile時に実行される関数に書けば compile時に召喚できる
  3. summon = fn mod -> defmodule Module.concat(Kanzen, mod) do def

    say() do IO.puts("#{__MODULE__}した^ω^") end end end summon.(Rikai) Kanzen.Rikai.say() # Elixir.Kanzen.Rikaiした^ω^
  4. summon = fn mod -> defmodule Module.concat(Kanzen, mod) do def

    say() do IO.puts("#{__MODULE__}した^ω^") end end end summon.(Rikai) Rikai.say() # Elixir.Kanzen.Rikaiした^ω^ モジュール名の動的な名前付けも可能 モジュールの親子関係はModule.concat/2を使う 文字列からモジュール名つける場合は Module.concat/1が使える
 iex> Module.concat(["Hoge"]) Hoge

  5. summon = fn fun_name -> defmodule Hoge do def unquote(fun_name)(arg)

    do IO.puts("#{unquote(fun_name)}#{arg}です") end end end summon.(:hoge) Hoge.hoge("fuga") # hogefugaです
  6. summon = fn fun_name -> defmodule Hoge do def unquote(fun_name)(arg)

    do IO.puts("#{unquote(fun_name)}#{arg}です") end end end summon.(:hoge) Hoge.hoge("fuga") # hogefugaです unquoteを使えば関数名を動的に生成できる
 unquoteはASTに式を注入するもの
 イメージは文字列に変数を展開するのと同じ感じ
  7. summon = fn funs -> defmodule Tamanugi do Enum.each(funs, fn

    fun -> def unquote(fun)(arg), do: :ok end) end end summon.([:hoge, :fuga, :piyo]) Tamanugi.module_info(:exports) # [fuga: 1, hoge: 1, piyo: 1, ...] Tamanugi.fuga() # :ok
  8. summon = fn funs -> defmodule Tamanugi do Enum.each(funs, fn

    fun -> def unquote(fun)(arg), do: :ok end) end end summon.([:hoge, :fuga, :piyo]) Tamanugi.module_info(:exports) # [fuga: 1, hoge: 1, piyo: 1, ...] Tamanugi.fuga() # :ok Enum.each/2を使うことで複数の 関数を生成することも可能!!
  9. summon = fn args -> defmodule Hoge do vars =

    Enum.map(args, fn arg -> arg |> String.to_atom |> Macro.var(__MODULE__) end) def say(unquote_splicing(vars)) do IO.inspect unquote(vars) end end end summon.(["arg1", "arg2", "arg3"]) Hoge.say(1, 2, 3) # [1, 2, 3]
  10. summon = fn args -> defmodule Hoge do vars =

    Enum.map(args, fn arg -> arg |> String.to_atom |> Macro.var(__MODULE__) end) def say(unquote_splicing(vars)) do IO.inspect unquote(vars) end end end summon.(["arg1", "arg2", "arg3"]) Hoge.say(1, 2, 3) # [1, 2, 3]
  11. summon = fn args -> defmodule Hoge do vars =

    Enum.map(args, fn arg -> arg |> String.to_atom |> Macro.var(__MODULE__) end) def say(unquote_splicing(vars)) do IO.inspect unquote(vars) end end end summon.(["arg1", "arg2", "arg3"]) Hoge.say(1, 2, 3) # [1, 2, 3] unquote_splicingを使えば複数引数の関数も生成できる 引数は Macro.var/2 を使ってASTにしておく必要がある