やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

【第7回清流elixir勉強会@fukuoka.exさん】Elixirのシギルについて調べて色々試した【リモートでジョイン】

トピック

昨週に引き続き、清流elixirの第7回目の勉強会を開催させて頂きました
今回は清流elixirのみではなく福岡を拠点に活動されているfukuoka.exさんのもくもく会
リモートでジョインさせて頂きました

fukuokaex.connpass.com

もくもく会を主催されているkogaさん
色々とご準備頂きまして有難うございました

なんと昨日のリモートのもくもく会

  • 北海道
  • 東京
  • 愛知
  • 高知
  • 福岡

が繋がったらしいです。実質日本一週ですわ

それで僕はElixirのシギルたるものがずっと気になっていたのでもくもくとまとめた
ほとんど、喋りながらやってた気がする笑

シギルって

そもそもシジル? シギルどっち?
両方存在してるけどどっちが正しいのか?
(プログラミングelixirではシジルだけど...)

とりあえず以下、シギルとして扱う

「~」を先頭に書くことでシギルというものを扱うことが可能
プログラミングelixirによると

  • ~C
  • ~c
  • ~S
  • ~s
  • ~W
  • ~w
  • ~r
  • ~R

の4種類(小文字と大文字)が用意されている
とりあえず~sは動いた

~s(hello world)
# "hello world"

いろいろと試しつつ動かしてみる

~sと~Sについて

さきほどは~sに英字を渡したが日本語でも問題なくいけた

~s(こんにちは)
# "こんにちは"

数値でも問題ない模様

~s(114514)
# "114514"

~sと~Sの違いは?

~sをつかうと演算やら値の埋め込みしてくれるようだ
1/2(0.5)の演算結果が出力値に含まれている

~s(hello world #{1 / 2})
# "hello world 0.5"

変数の埋め込みも問題ない

val = "okb"
~s(hello world #{val})
# "hello world okb"

合わせて""やら''を使えるっぽい

~s(hello world #{"okb"})
# "hello world okb"

~s(hello world #{'okb'})
# "hello world okb"

~Sの場合は演算やら値の埋め込みは行われない

~S(hello world #{1 / 2})
# "hello world \#{1 / 2}"

~Sは変数名や関数名を文字列に変換するのに便利そう
基本的には~sの方が使い勝手は良さげですね

~cと~Cについて

~cの場合はシングルクオートで表示される
これは文字リストというものらしく、~s(string)とは仕様が異なる
文字リストに関しては下記に改めて記述する
~cでも同様に演算渡せるっぽい

~c(hello world)
# 'hello world'
~c(hello world #{1/2})
# 'hello world 0.5'

~Cの場合はやはり値の埋め込みが出来ない

~C(hello world #{1/2})
# 'hello world \#{1/2}'
~C(hello world)
# 'hello world'

ここまでで分かったことは

  • ~sのような小文字のものは値の埋め込みや演算が可能
  • ~Sのような大文字のものはそのまま出力される

ということ

シギルをStringモジュールに渡せるかどうか

どうやら~cだとerrorになってしまう
これは文字リストであって文字列ではないからということ

String.first(~c(hello world))
# (FunctionClauseError) no function clause matching in String.Unicode.next_grapheme_size/1

~sだとStringモジュールが使えた
やはり~sはstringとして扱われている

String.first(~s(hello world))
# "h"
String.graphemes(~s(hello world))
# ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]

パイプで遊べた(最高

String.graphemes(~s(hello world)) |> Enum.filter(&(&1 == "h"))
# ["h"]

文字リストについて

文字列はUTF-8エンコードされたバイナリ
文字リストは文字(コードポイント)のリスト

なるほど完全に理解した(すっとぼけ
文字リストは``で囲ってあげるとシギルでなくても作れるらしい
コードポイントってなんやねん~
?a(アルファベット)と記述することでコードポイントを確認することが可能

?a
# 97

?b
# 98

?c
# 99

何か出た。逆でも出た

[98]
# 'b'

厳密に考えるとリストin数値が文字リストとして扱われているということか
''で囲われているからstringではないということになるので普通にEnumやらが使えるということ?

'okb' |> Enum.map(&(IO.puts(&1)))
111
107
98
# [:ok, :ok, :ok]

おお、思った通りにEnumが使える
ただの数値として文字リストの要素が扱われているかどうかを確認してみる

Enum.map('okb', &(is_integer(&1)))
# [true, true, true]

ということなので以下が通る

Enum.sum('okb')
# 316

長くなりそうなので文字リストに関しては今回のテーマとそれるので、ここらへんで終了
文字をリストで扱えることに気づく
使い道はまだ思いつけていない。便利そうでまだ、うーんって感じ

~wと~Wについて

~wとすることで受け取った情報がリストに変換されている

~w[hello world okb]
["hello", "world", "okb"]

やはり受け渡しが出来た

val = "okb"

~w[hello world #{val}]
["hello", "world", "okb"]

~Wでは...もう語ることはない

~W[hello world #{val}]
["hello", "world", "\#{val}"]

リストになるのでもちろんパイプで遊べる(最高

~w[hello world #{val}]
|> Enum.filter(&(String.length(&1) > 4))
|> Enum.reduce(&(&2 <> &1))
"helloworld"

どうやら最後に付け合わせる文字でモードが変わる模様

  • a -> atom
  • c -> string list
  • s -> string
#a
~w[hello world #{val}]a
[:hello, :world, :okb]

#c
~w[hello world #{val}]c
['hello', 'world', 'okb']

#s
~w[hello world #{val}]s
["hello", "world", "okb"]

これは便利
String.splitでは全てがstringになるのでatomを生成できれば
マップのkeyを生成したりと使い道は色々とありそう

以上、シギルについて2時間で調査できた内容です

今回の勉強会の感想

もくもく会には何回か参加したことがあったが、リモートでの勉強会参加は初めてだった
あまり表に顔は出す人間ではないが非常に新鮮で同じものに興味のある方と共に学べたことが素晴らしい体験だった

ぜひまた参加したいです
fukuoka.exさんが月1回程度の頻度で開催されていらっしゃるので
ぜひ会場(全国各地)でお会いしましょう