LoginSignup
14
17

More than 5 years have passed since last update.

すごいE本をElixirでやる(1章)

Last updated at Posted at 2014-08-11

自分の日記で書いているすごいE本をElixirでやるの1章が終わったのでまとめる.

宣伝

Elixir に興味を持ったら,だいたい毎週木曜日に ErlangVM に載っている言語に関する話題やそうでない話題でわいわいやる集まり Sapporo.beam にも遊びにきてね.

たいしたことはできないけど,一緒に悩んだりはできる.

1章

1.1 Erlang シェルを使ってみる

  • Erlang の erl 相当のものは Elixir だと iex
  • Erlang の help(). は Elixir だと h()
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> h()

                                  IEx.Helpers                                   

Welcome to Interactive Elixir. You are currently seeing the documentation for
the module IEx.Helpers which provides many helpers to make Elixir's shell more
joyful to work with.

This message was triggered by invoking the helper h(), usually referred to as
h/0 (since it expects 0 arguments).

There are many other helpers available:

  • c/2       — compiles a file at the given path
  • cd/1      — changes the current directory
  • clear/0   — clears the screen
  • flush/0   — flushes all messages sent to the shell
  • h/0       — prints this help message
  • h/1       — prints help for the given module, function or macro
  • l/1       — loads the given module's beam code and purges the current
    version
  • ls/0      — lists the contents of the current directory
  • ls/1      — lists the contents of the specified directory
  • pwd/0     — prints the current working directory
  • r/1       — recompiles and reloads the given module's source file
  • respawn/0 — respawns the current shell
  • s/1       — prints spec information
  • t/1       — prints type information
  • v/0       — prints the history of commands evaluated in the session
  • v/1       — retrieves the nth value from the history
  • import_file/1
    ┃         — evaluates the given file in the shell's context


Help for functions in this module can be consulted directly from the command
line, as an example, try:

┃ h(c/2)

You can also retrieve the documentation for any module or function. Try these:

┃ h(Enum)
h(Enum.reverse/1)

To learn more about IEx as a whole, just type h(IEx).

1.2 Erlang の基礎をいくつか

数値型

  • Erlang と異なり divrem を中置演算子として使えないので,div(5, 2)rem(5, 2) のようにする
  • 基数は 0b から始めると 2 進数, 0o から始めると 8 進数, 0x から始めると 16 進数になる
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 2 + 15
17
iex(2)> 49 * 100
4900
iex(3)> 1892 - 1472
420
iex(4)> 5 / 2
2.5
iex(5)> div(5, 2)
2
iex(6)> rem(5, 2)
1
iex(7)> (50 * 100) - 4999
1
iex(8)> -(50 * 100 - 4999)
-1
iex(9)> -50 * (100 - 4999)
244950
iex(10)> 0b101010
42
iex(11)> 0o677
447
iex(12)> 0xae
174
  • 変数は小文字で書く.大文字で書くとエラーになる.
  • two = two + 1 がエラーにならないで再束縛される.Elixr で再束縛させないなら ^ から始まる pin operator というのを使う.
  • 変数を「消す」 f(Variable). は iex にはなさそうだ(知ってたら教えてほしい).
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> one = 1
1
iex(2)> un = uno = one = 1
1
iex(3)> two = one + one
2
iex(4)> two = 2
2
iex(5)> two = two + 1
3
iex(6)> two
3
iex(7)> two = 2
2
iex(8)> ^two = two + 1
** (MatchError) no match of right hand side value: 3

iex(8)> ^two = one + 1
2
iex(9)> 47 = 45 + 3
** (MatchError) no match of right hand side value: 48

iex(9)> Two = 2
** (MatchError) no match of right hand side value: 2

iex(9)> f(two)
** (RuntimeError) undefined function: f/1

アトム

  • Erlang だと小文字で書くだけでアトムになる.だから変数名を小文字で始められない.
  • Elixir は変数名を小文字で始められる,そのかわりアトムは : から始める.
  • Erlang だとシングルクォートで囲った値もアトムになる.
  • Elixir では : で始まるダブルクォートで囲った値もアトムになる.
Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :atom
:atom
iex(2)> :atoms_rule
:atoms_rule
iex(3)> :atoms_rule@erlang
:atoms_rule@erlang
iex(4)> :"Atoms can be cheated!"
:"Atoms can be cheated!"
iex(5)> :atom = :"atom"
:atom

ブール代数と比較演算子

Elixir の演算子は 3 Basic operators を見るとわかりやすい.

  • and or は使えるけど,Erlang と違って短絡演算子になってる
  • xor は使えなくなっていた(たぶん 0.15.0 から)
  • Elixir では厳密な比較に ===!== を使う.厳密でない比較に ==!= を使う.
  • Erlang とは違い 1 >= 1 に対応するのは 1 <= 1 で等号の位置が入れ替わったりしない.
  • Erlang と同じで truefalse はシンボルである.

おまけ.

Elixir では true false 以外でも扱える &&|| が用意されている.その場合は falsenil だけが偽として扱われる.Ruby と同じ.

Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> true and false
false
iex(2)> false or true
true
iex(3)> true xor false
** (SyntaxError) iex:3: syntax error before: 'xor'

iex(3)> not false
true
iex(4)> not (true and true)
false
iex(5)> 5 === 5
true
iex(6)> 1 === 0
false
iex(7)> 1 !== 0
true
iex(8)> 5 === 5.0
false
iex(9)> 5 == 5.0
true
iex(10)> 5 != 5.0
false
iex(11)> 1 < 2
true
iex(12)> 1 < 1
false
iex(13)> 1 >= 1
true
iex(14)> 1 =< 1
** (SyntaxError) iex:14: syntax error before: '<'

iex(14)> 1 <= 1
true
iex(15)> 5 + :llama
** (ArithmeticError) bad argument in arithmetic expression
    :erlang.+(5, :llama)
iex(15)> 5 === true
false
iex(16)> 1 < false
true
iex(17)> 1 and 2
** (ArgumentError) argument error: 1

iex(17)> 1 && 2
2
iex(18)> 1 || 2
1
iex(19)> false || 2
2

タプル

特に違わないので iex の結果は貼らない.

iex の結果が見たければすごいE本をElixirでやる(4)には貼ってある.

リスト

Erlang と Elixir であんまり変わらないので iex の結果は貼らない.

iex の結果が見たければすごいE本をElixirでやる(4)には貼ってある.

[223] が Erlang だと “é” と表示されるが,Elixir だとそのまま [223] と表示されたところだけ違った.

Elixir でも

iex(1)> <<233 :: utf8>>
"é"

とすれば同じように値を表現することはできる.(あんまりやらないだろうけど)

詳しくは 6 Binaries, strings and char lists に書いてある.

リスト内包表記

Elixir の内包表記のドキュメントは 18 Comprehensions にある.

おまけ.

Elixir は範囲を表記するのに 1..10 をつかえる.詳しくは Range に書いてある.

Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> for n <- [1, 2, 3, 4], do: 2 * n
[2, 4, 6, 8]
iex(2)> for x <- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], rem(x, 2) === 0, do: x
[2, 4, 6, 8, 10]
iex(3)> restaurant_menu = [{:steak, 5.99}, {:beer, 3.99}, {:poutine, 3.50}, {:kitten, 20.99}, {:water, 0.00}]
[steak: 5.99, beer: 3.99, poutine: 3.5, kitten: 20.99, water: 0.0]
iex(4)> for {item, price} <- restaurant_menu, price >= 3, price <= 10, do: {item, price * 1.07}
[steak: 6.409300000000001, beer: 4.2693, poutine: 3.745]
iex(5)> for x <- [1, 2], y <- [3, 4], do: x + y
[4, 5, 5, 6]
iex(6)> weather = [{:tronto, :rain}, {:montreal, :storms}, {:london, :fog}, {:paris, :sun}, {:boston, :fog}, {:vancouver, :snow}]
[tronto: :rain, montreal: :storms, london: :fog, paris: :sun, boston: :fog, vancouver: :snow]
iex(7)> foggy_places = for {x, :fog} <- weather, do: x
[:london, :boston]
iex(8)> for x <- 1..10, do: x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

ビット構文

Elixir のバイナリのパターンマッチは Kernel.SpecialForms.<<>>/1 が詳しい.

Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> color = 0xf09a29
15768105
iex(2)> pixel = <<color::24>>
<<240, 154, 41>>
iex(3)> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(4)> <<pix1, pix2, pix3, pix4>> = pixels
** (MatchError) no match of right hand side value: <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>

iex(4)> <<pix1::24, pix2::24, pix3::24, pix4::24>> = pixels
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(5)> <<r::8, g::8, b::8>> = <<pix1::24>>
<<213, 45, 132>>
iex(6)> r
213
iex(7)> <<r::8, rest::binary>> = pixels
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(8)> r
213
iex(9)> rest
<<45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(10)> <<x1::unsigned>> = <<-44>>
<<212>>
iex(11)> <<x1::utf8>>
"Ô"
iex(12)> <<x2::signed>> = <<-44>>
<<212>>
iex(13)> x2
-44
iex(14)> <<x2::integer-signed-little>> = <<-44>>
<<212>>
iex(15)> x2
-44
iex(16)> <<n::8-unit(1)>> = <<72>>
"H"
iex(17)> n
72
iex(18)> <<n::integer>> = <<72>>
"H"
iex(19)> <<y::4-little-unit(8)>> = <<72, 0, 0, 0>>
<<72, 0, 0, 0>>
iex(20)> y
72

ビット単位のバイナリ操作

Elixir でのバイナリ演算は Bitwise が担っている.

Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> use Bitwise
nil
iex(2)> 0b00100 = bsl 0b0010, 1
4
iex(3)> 0b00001 = bsr 0b0010, 1
1
iex(4)> 0b10101 = bor 0b10001, 0b00101
21

バイナリ文字列

特に語ることがない.

Elixir では String を眺めるとよい.

バイナリ内包表記

Elixir でのバイナリ内包表記の概要は 18.2 Bitstring generators を眺めるとよい.

さらに詳しく知りたければ Kernel.SpecialForms.for/1 を見るとよい.

Elixir の内包表記は何も指定しないと常にリストが返るので,バイナリを返したいときには into を指定すること.

上に挙げた Kernel.SpecialForms.for/1 に書いてある.

Interactive Elixir (0.15.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> for <<x <- <<1,2,3,4,5>> >>, rem(x, 2) === 0, do: x
[2, 4]
iex(2)> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(3)> rgb = for <<r::8, g::8, b::8 <- pixels >>, do: {r, g, b}
[{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
iex(4)> for {r, g, b} <- rgb, into: "", do: <<r::8, g::8, b::8>>
<<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
iex(5)> for bin <- [<<3, 7, 5, 4, 7>>], into: "", do: <<bin>>
** (ArgumentError) argument error

iex(5)> for bin <- [<<3, 7, 5, 4, 7>>], into: "", do: <<bin::binary>>
<<3, 7, 5, 4, 7>>
iex(6)> for << x <- <<3, 7, 5, 4, 7>> >>, into: "", do: <<x+1::integer>>
<<4, 8, 6, 5, 8>>
14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17