macro with elixir@k1complete
about elixir elixirはErlang/OTP上に構築された、マクロを始めとするメタ プログラミング機能を特徴とする、Ruby風味の文法の言語。 Erlangを拡張するというよりも、Erlangの隣に別の言語を構築 して、相互に利...
about loop/recurloop/recurは簡単な再帰をその場で記述できるようなspecial formで、Clojure由来のもの。無名関数に対する再帰にまつわる問題ををまろやかに解決しているスマートな機能。ただし、便利すぎて使い方...
usage loop/recur たとえばfibonacchi数を求めるコード片              loop y doで、1変数の再帰ループで、初期値はyであることを示している。  loop y do        0 -> 0    c...
Impact of deprecate loop/recurloop/recurがelixir-0.6.0でdeprecatedとなり、0.7.0ではspecial formから取り除かれることになった。  遅いから  special form...
loop/recur, do it yourself! loop/recurがない場合、どうするか?  等価なコードはこんな感じ(fibonacchi数を例にとると)    f = fn(f, e) -> case e do        0->...
mloop/mrecurマクロによるloop/recurをmloop/mrecurとする構造は、mloop x, do: blockとなっている。block中に、パターンマッチを書き、再帰の指示をmrecur(param)として示すことになる。...
homoiconic syntax in elixircode elixirはhomoiconic構文であり、任意のelixirコードはelixirのデータ構造 で記述可能。これを勝手に”the tuple”と呼ぶ。  { function, ...
consider translation rule Elixir構文木タプルでのパーツ表現   変数に格納した関数オブジェクトを呼び出すためには、”.”演算子を適用する   が、これは、Elixir構文木タプルとしては、{:”.”, Line,...
traversal elixir tree 行きがけ順に構文木タプルをなぞり、パターンを認識したら、置き換えるようにす ればいい。 def traverse(a, f) do    r = f.(a) ## <-- パターンを認識して置き換える...
build mloopmb = traverse(block, fn(x) -> case x do  {:mrecur, line, args} when is_list(args) -> ## パターン    {{:”.”, line, [...
build mloop 2defmacro mloop(p, block) do   mb = traverse(block,...) # ブロックをトラバースしてパターン置き換え   quote do      mrecur = fn(mre...
macro utility Macro.expand(quote(do: ....), __ENV__)   コード片にマクロを一段階だけ適用したコード片   (“The tuple”)を返す。__ENV__は解釈する環境で通常   はこのまま...
demo
mloop/mrecur limitation loopはloop/n+1というアリティを持つのに対して、 mloopはmloop/2というアリティを持つ。つまり、変 数を一つしか持てない。複数欲しい場合はタプルを 渡すことになる。 それ以外は...
Upcoming SlideShare
Loading in …5
×

Elixir macro-in-action-1

980 views
872 views

Published on

elixir macro introdution

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
980
On SlideShare
0
From Embeds
0
Number of Embeds
37
Actions
Shares
0
Downloads
2
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Elixir macro-in-action-1

    1. 1. macro with elixir@k1complete
    2. 2. about elixir elixirはErlang/OTP上に構築された、マクロを始めとするメタ プログラミング機能を特徴とする、Ruby風味の文法の言語。 Erlangを拡張するというよりも、Erlangの隣に別の言語を構築 して、相互に利用可能にしている。JavaとScalaのような関 係。 今回、loop/recurという機能をテーマにelixirの持つ機能の特徴 を紹介する
    3. 3. about loop/recurloop/recurは簡単な再帰をその場で記述できるようなspecial formで、Clojure由来のもの。無名関数に対する再帰にまつわる問題ををまろやかに解決しているスマートな機能。ただし、便利すぎて使い方が難しい面もある。
    4. 4. usage loop/recur たとえばfibonacchi数を求めるコード片 loop y doで、1変数の再帰ループで、初期値はyであることを示している。 loop y do 0 -> 0 cond doパターンと同様にパターンマッチで記述。 yが0なら0, 1なら1,それ以外のxなら、という形で記述。 1 -> 1 x -> recur(x-1) + recur(x-2) end loopの再帰を行う際のパラメータを指定する。関数を定義する事無く再帰している。so, cool!!!
    5. 5. Impact of deprecate loop/recurloop/recurがelixir-0.6.0でdeprecatedとなり、0.7.0ではspecial formから取り除かれることになった。 遅いから special formは可変個の引数を持てたり、オーバライドされなかっ たり、特別なスコープを持ったりした特別なものなので、数を減 らしたい。 関数定義すればいいじゃんうわーん
    6. 6. loop/recur, do it yourself! loop/recurがない場合、どうするか? 等価なコードはこんな感じ(fibonacchi数を例にとると) f = fn(f, e) -> case e do 0->0 1->1 e -> f.(f, e-1) + f.(f, e-2) end end f.(f, y) 自分でloop/recurを実装してみる。そのためのマクロだw
    7. 7. mloop/mrecurマクロによるloop/recurをmloop/mrecurとする構造は、mloop x, do: blockとなっている。block中に、パターンマッチを書き、再帰の指示をmrecur(param)として示すことになる。上記mloop x, do: blockの展開コードは、以下のようになってほしい。 mblock = block中のrecur(arg)をf.(f,arg)に書き換えたものとする。 f = fn(f, x) do mblock end f.(f, x)
    8. 8. homoiconic syntax in elixircode elixirはhomoiconic構文であり、任意のelixirコードはelixirのデータ構造 で記述可能。これを勝手に”the tuple”と呼ぶ。 { function, line, [arg1,args2,...] } function: 関数を表すアトムか、”the tuple” line: 現在のソースコード上の行番号 arg1, arg2: functionへの引数で、アトムか、”the tuple”で可変個 elixirの任意のコード片は一つの”the tuple”で表せる。
    9. 9. consider translation rule Elixir構文木タプルでのパーツ表現 変数に格納した関数オブジェクトを呼び出すためには、”.”演算子を適用する が、これは、Elixir構文木タプルとしては、{:”.”, Line, [変数]}となる。 変数自体は、{:変数名, Line, :quoted}という構造になる。 一方、関数呼び出しは、{:関数名, Line, [args]}となる。 まとめると mrecur xは {:mrecur, Line, [{:x, Line, :quoted}]} これを、以下のようにすればいい {{:”.”, Line, [{:mrecur, Line, :quoted}]}, Line, [{:mrecur, Line, :quoted},{:x, LIne, :quoted}]}
    10. 10. traversal elixir tree 行きがけ順に構文木タプルをなぞり、パターンを認識したら、置き換えるようにす ればいい。 def traverse(a, f) do r = f.(a) ## <-- パターンを認識して置き換える関数 cond do is_tuple(r) -> list_to_tuple(traverse(tuple_to_list(r), f)) is_list(r) -> :lists.map(fn(x) -> traverse(x, f) end, r) true -> r end end
    11. 11. build mloopmb = traverse(block, fn(x) -> case x do {:mrecur, line, args} when is_list(args) -> ## パターン {{:”.”, line, [{:mrecur, line, :quoted}]}, line, [{:mrecur, line, :quoted}|args]} _ -> x end end)
    12. 12. build mloop 2defmacro mloop(p, block) do mb = traverse(block,...) # ブロックをトラバースしてパターン置き換え quote do mrecur = fn(mrecur, x) -> # mrecurという名前の変数で無名関数を作成 case(x, unquote(mb)) # 置き換えたblock end mrecur.(mrecur, unquote(p)) # loop pのp endend
    13. 13. macro utility Macro.expand(quote(do: ....), __ENV__) コード片にマクロを一段階だけ適用したコード片 (“The tuple”)を返す。__ENV__は解釈する環境で通常 はこのまま。 Macro.to_binary({“The tuple”}) “The tuple”形式のタプルをelixirのソース形式の文字 列へ変換したものを返す。
    14. 14. demo
    15. 15. mloop/mrecur limitation loopはloop/n+1というアリティを持つのに対して、 mloopはmloop/2というアリティを持つ。つまり、変 数を一つしか持てない。複数欲しい場合はタプルを 渡すことになる。 それ以外はloop/recurと同じ機能を持つ, yeah! o/

    ×