トピック
昨日、愛知県の丸の内にて私が運営しているコミュニティ清流elixirで
第3回目となる勉強会を開催させて頂きました
さすがに3回目ともなると多少は要領が分かってきてわりとスマートに
活動できるようになってきたかと思ってます(力不足ですません
清流elixir-infomation
開催場所: 丸の内(愛知)
人数: 2 -> 3
コミュニティ参加人数 : 3 -> 5 update!!
20190427現在
第3回の活動内容
今回は前回の勉強会中につまづいたマップのパターンマッチについて学習しました
どうすればマップから指定のkeyを持つデータをマッチできるのかをいろいろ試した
ただElixirにはマップの記述方法が2種類あり、それぞれで取得の仕方が微妙に異なるので注意
それぞれに名称も特になく勝手に命名しておく
Rubyにも同様に2種類の記述方法があるようで
それは歴史的な流れでより簡単に記述するためにということで
Elixirでいうアトム式が誕生したとのこと
使い分けについて議論しましたが完璧な答えは出なかった
温故知新スタイルでは記号でも日本語でも何でも(バイナリ)をkeyにできるが
それにメリットがあるかは分からなかった
どちらを使うにしろチームで統一して使えばいいんじゃね?という結論になりました
Atom式からのマッチング
このマップデータから:nameのkeyを様々な方法でマッチしてみる
info = %{name: "nobunaga", age:45}
1.最もシンプルなマッチ
info[:name] #nobunaga #この書き方はerror info[name] #error #存在しないkeyをマッチさせようとしてもerrorにはならない info[:company] #nil
2.次にシンプルなマッチ
info.name #nobunaga #存在しないkeyをマッチさせようとするとerror info.company #error
3.keyの存在を確認しつつのマッチ
#%{key_name: variable_name} = data %{name: name} = info name #nobunaga #変数名は自由(アンダースコアはNG) %{name: human_name} = info human_name #nobunaga
4.Map.getを使う
Map.get(info, :name) #nobunaga #第2引数にはAtomで渡す必要がある(errorにはならない) Map.get(info, "name") #nil
5.Map.fetchを使う
#マッチに成功した場合に{:ok, value}のタプルで返ってくる Map.fetch(info, :name) # {:ok, value} {judge, name} = Map.fetch(info, :name) name #nobunage #存在しないkeyを指定した場合は:errorのみが返ってくる Map.fetch(info, :company) # :error
温故知新スタイルからの取得
info = %{"name" => "nobunaga", "age" => 45}
同様にAtom式の5つのやり方を試してみる
1.最もシンプルなマッチ
info["name"] #nobunaga info[:name] #nil
2.次にシンプルなマッチ
実はAtom式でないとこれは使えない
info."name" #error #警告がでる上に失敗する warning: found quoted call "name" but the quotes are not required. Calls made exclusively of Unicode letters, numbers, and underscore do not require quotes iex:40 ** (KeyError) key :name not found in: %{"name" => "nobunaga"}
3.keyの存在を確認しつつのマッチ
#記述の仕方がAtom式と異なるので注意 %{"name" => n} = info n #nobunaga #存在しないとやはりerror %{"company" => c} = info #error
4.Map.getを使う
#第2引数にはkeyと同様の型で渡す(今回はstring) Map.get(info, "name") #nobunaga #errorにはならない Map.get(info, name)
5.Map.fetchを使う
Map.fetch(info, "name") #{:ok, "nobunaga"} #やっぱり存在しないと:error Map.fetch(info, "company") # :error
基礎を踏まえてデータで遊ぶ
info = %{"name" => "nobunaga", "age" => 45, "from" => "gifu", "style" => "bushidou"}
このデータから"name"と"from"を取得して
"name"と"from"の値を結合することに(stringの結合)
name = "nobunaga" from = "gihu" name <> from # nobunagegihu
温故知新スタイルであることを留意して取り組むとこんな感じになった
info["from"] <> info["name"] #nobunagegihu Map.get(info, "from") <> Map.get(info, "name") #nobunagegihu {a, b} = Map.fetch(info, "name") {c, d} = Map.fetch(info, "from") b <> d #nobunagegihu
前回のリベンジ
前回はリストinマップから値をマッチするという作業でつまづいた
これだけ知識がついたのでリベンジするかということでリストinマップの情報を用意
info = [ %{age: 22, height: 180, name: "a"}, %{age: 16, height: 142, name: "b"}, %{age: 43, height: 165, name: "c"}, %{age: 67, height: 156, name: "d"}, %{age: 81, height: 161, name: "e"}, %{age: 8, height: 126, name: "f"} ]
リスト内の各データへのアクセスをするためにはもちろんEnumを使う
あとは今までやってきたようにマップのkeyを使ってマッチさせるだけ
Enum.map(infos, fn row -> row.age end) #[22, 16, 43, 67, 81, 8] Enum.map(infos, fn row -> row[:age] end) #[22, 16, 43, 67, 81, 8] Enum.map(infos, &(&1.age)) #[22, 16, 43, 67, 81, 8] Enum.map(infos, fn row -> Map.get(row, :age) end) #[22, 16, 43, 67, 81, 8]
もう楽勝ですね
このマッチは一瞬で終わってしまった
なぜ関数型言語がいいのかって
作業を進めている中で参加者の業界20年のベテランの方から
オブジェクト言語に疲れたという話がはじまり、かなり盛り上がった
動物や車などがオブジェクトのサンプルとしてよく挙げられる
しかし、機械の操作や目に見えない概念をオブジェクトにして考えるということは
難しい上に正解がなく、人それぞれで理解しにくい場合が多いとのこと
そうすると流れの掴みやすい関数型の良さがよく分かるとのことで
「なるほどなー」と強く感銘を受けました
まとめ
今回はマップのパターンマッチについて勉強会を行いました
途中から会話が無くなり少年のように没頭する時間がおもろかった
それぞれが様々な記述を発見していく感じも良かった
僕が目指している「開催者<=>参加者」という構図が少し見えてきたがする
次回はGW明けの5/10(金)の19:30からの開催予定です
お気軽に覗きにきてください