トピック
第13回目の清流elixirの勉強会を開催しました
今回はOSSのコードを読んでElixir力をあげるという目的かつ、弊コミュニティ初の試みとしてリモート(Zoom)での参加にも対応しました
これで全国からのジョインが可能に!! 勉強会の当日は東海と九州が繋がり、事実上の中部から西日本を制覇したことになった。すごい
初のリモート開催のためZoomに手馴れておらず、バタついてしまいました。申し訳ありません。次はもっとスマートに出来るかと思いますので多めに見て頂きたいですm( )m
清流elixir-infomation
開催場所: 丸の内(愛知)
参加人数: 5 -> 8 update!! コミュニティ参加人数 : 16 -> 21 update!
20191026現在
第13回の勉強会の内容について
コードを早く、美しく形に出来るようにするためには、コードを書く経験を積むことも重要だが、達人のコードを読むという経験も非常に重要だと考えている。Elixirの基礎的な文法に関してはある程度、習得が完了したはずなので、Elixirを使って書かれたOSSのコードで実際にどのような記述が現れてくるのかを、1人だと辛いので、集まって読んでみるかという流れに
時間の都合もあるので、コード量が多すぎず、コード量が少なすぎず、かつOSSの内容が比較的分かりやすいものを用いたいということで、私の独断と偏見でTrotというphoenixとは異なるmicro web frameworkのOSSを選択しました
まず先に得られた結果・知見から
...
俺の知っているElixirと違う...
なんじゃこれ。知らないことばっかりなんですが、それは..
syntaxに関しては概ね把握しているつもりであったし、Enumでパイプ使って脳汁ブシャーッってのも気持ちよく出来るレベルなんで、まぁ読めるやろと思ってたけど、自分のレベルを思い知らされた
特に苦労したのがmacroに関しての理解。存在は知っているし、プログラミングElixirでも扱われているトピックだったので、うっすら頭に知識があるはずだが実際のところ黒魔術的要素が強いのでユースケースまでが想定できていなかった
Trotの内部の至る所にmacroがふんだんかつ、おしゃれに使われており、頭が????となった
最初に遭遇した頭を悩ませた問題のコードは以下になる
./trot/lib/trot/trot.exより抜粋
# module変数 -> 許可するmethod @http_methods [:get, :post, :put, :patch, :delete, :options] @doc """ Returns a boolean indicating whether the passed in atom is a valid HTTP method. """ defmacro is_http_method(thing) do quote do # unquote(module.func) |> is_atom() # get, post, patch, delete # unquote -> thing -> 実体化(http_methodsのどれかであれば) # return -> boolean # Q: macroの使うタイミングむずすぎ問題 -> if(macro!!), for(macro!!), def(macro), defmacro(macro) ????? is_atom(unquote(thing)) and unquote(thing) in unquote(@http_methods) end end
このis_http_method(thing)というものがboolの値を返していることは何となく分かるが、なぜここでmacroなのかという疑問は残る
普通にis_atom()
の判定と@http_methods
に引数の値が含まれているかどうかが分かれば良いだけではないのか?
なので以下のように書き直しても問題ないはずだが、macroが実行時評価になるという話が関係するのだろうか、いずれにしろ現段階では弱すぎて理解が出来ていないのでレベル上げをしないといけない
defmodule Sample do @http_methods [:get, :post, :put, :patch, :delete, :options] def is_http_method(thing) do is_atom(thing) and thing in @http_methods end end Sample.is_http_method(:get) |> IO.puts() # true
このSampleを書いて、TrotのREAD.MEにあるエンドポイントのサンプルを見てみて1つ思ったことは、このget "/hello", do: "hello"
というものがmacroでsyntaxを定義しており、この記述が解釈されてAST(構文抽象木)に変換(elixirの場合は3つの値をもつタプルだった気がする)されるみたいな話しが絡んでくるんだろうなぁと。勉強しよう
ちなみに先ほどのdefmacro
はこんな感じで呼び出せた
defmodule Trot do @http_methods [:get, :post, :put, :patch, :delete, :options] @doc """ Returns a boolean indicating whether the passed in atom is a valid HTTP method. """ defmacro is_http_method(thing) do quote do # unquote(module.func) |> is_atom() # get, post, patch, delete... # unquote -> thing -> 実体化(http_methodsのどれかであれば) # return -> boolean # Q: macroの使うタイミングむずすぎ問題 -> if(macro!!), for(macro!!), def(macro), defmacro(macro) ????? # IO.puts(thing) IO.puts(unquote(thing)) is_atom(unquote(thing)) and unquote(thing) in unquote(@http_methods) end end end defmodule Call do import Trot def exec(), do: is_http_method(:get) end Call.exec() |> IO.puts() # true
知らない機能がたくさんある
Elixirってこんな風になってんの、そんなことができるのって機能が多すぎて驚いた
iex
を立ち上げた状態でh Enum
(hのあとはモジュール名とかsyntaxとか)としてやるとEnumに関するhelpを確認することが出来る
Enum Provides a set of algorithms to work with enumerables. In Elixir, an enumerable is any data type that implements the Enumerable protocol. Lists ([1, 2, 3]), Maps (%{foo: 1, bar: 2}) and Ranges (1..3) are common data types used as enumerables: iex> Enum.map([1, 2, 3], fn x -> x * 2 end) [2, 4, 6] iex> Enum.sum([1, 2, 3]) 6 iex> Enum.map(1..3, fn x -> x * 2 end) [2, 4, 6] iex> Enum.sum(1..3) 6 iex> map = %{"a" => 1, "b" => 2} iex> Enum.map(map, fn {k, v} -> {k, v * 2} end) [{"a", 2}, {"b", 4}]
同じようにh def
ってやってみるとdefってのがmacroで作られていることが分かる
defmacro def(call, expr \\ nil) Defines a function with the given name and body.
さらに驚いたのがh defmacro
と記述した時。defmacroがdefmacroによって作られている。なんだこれは笑
defmacro defmacro(call, expr \\ nil)
macroでめちゃ盛り上がる様子
defmacroは、いつだって、あなたの傍にいますよ😋 #清流elixir #kokuraex #fukuokaex
— piacere@DigiDock (love Elixir&Gravity+仮想世界創造機構) (@piacere_ex) 2019年10月25日
つまりは、Elixirのコードのどこかに本物のdefmacroがいるということになり、今日一上がった。defmacro
がdefmacro
を作っている。うーん。厨二病、素晴らしい...!!
Elixirのsyntaxは多くがmacroで記述されており、ElixirのKernel.exというファイルを見れば確認することが可能だ
IExとEEx
今まで知ることも触れることもなかったものだ
IExはElixirのiexに関する関数が扱えるようで、IEx.started?
とするとiexが立ち上がっているのかどうかがbool値で判定することが出来る
特に感動したのがEExの方で、このEExを使えば色々と面白いことが出来そうだ
EEx.eval_file(ex_file_path)
とすると.exに記述されているコードを文字列として取得することが出来る
iex> EEx.eval_file("mix.exs") "defmodule Trot.Mixfile do\n : : \"https://github.com/hexedpackets/trot\"},\n files: ~w(mix.exs README.md LICENSE lib VERSION)]\n end\nend\n"
当然、文字列なので|>
を使ってStringモジュールの関数を使用することが出来る
iex> EEx.eval_file("mix.exs") |> String.at(3) "m"
あと1つ文字列からコードを実行する関数があったが、何ていう名前だったのかど忘れしてしまった...
福岡のエンジニア強すぎるって
はぁ、、福岡のエンジニア強すぎる。elixirのことまぁまぁ分かってたつもりだったけど知らないことしか無かった。ということが分かったので今日は記念すべき1日。打倒macro。
— OKB (@sing_mascle69) 2019年10月25日
fukuoka.exの発足人のpiacereさんがElixirに関して知らないことがなくて、もう笑うしかない
twitter.com
東海(広すぎるので本当は岐阜と愛知)にElixirの知識をリモートで届けてくださり感謝しかありません
また今回リモートで参加してくださった方は皆さん、福岡の方(間違いありましたら申し訳ありません)で、いかに福岡でElixirに対して注目が集まってるのかが分かるし、議論している話のレベルも高くて驚くばかりだ...
良い感じで悔しい気持ちになれたのでホットなまま、維持していきたい。やる気がめっちゃ出た
総評
コードを一緒に読むのいいですね。自分の弱さ、何が分かっていないかが分かったので良しとする。まだまだ知らないことがあるんやなと高ぶった
こういう思いが出来るのも清流elixirを開催しある程度、継続してきたからだと身にしみる...
なんと10/30(水)にfukuoka.exさんが開催される秋のLT大会にリモートLTという形で登壇させて頂くことになりました!!
リモートLTって凄いな。初めて聞きました笑
半ば強引に枠に入れて頂けたようで恐縮です、ありがとうございます
「清流elixirのこれまで。なぜ東海でelixirをやるのか」みたいなタイトルでLTします。資料はどこかにアップしようと思うので、ごひいきに〜