読者です 読者をやめる 読者になる 読者になる

牌語備忘録 -pygo

あくまでもメモです。なるべくオフィシャルの情報を参照してください。

牌語備忘録 -pygo

すごE本を読んでみたメモ -- 第1章

Erlang

書籍『すごいErlangゆかいに学ぼう!/Learn You Some Erlang for great good! 』まとめ

第1章 始めましょう

1.1 Erlang シェルを使ってみる

  • $ erl
  • ヘルプの出し方1 help().
  • ヘルプの出し方2 ^G で終了して h
  • シェルがフリーズした場合には、 control-G i enter c enter
  • 式の最後は必 ずピリオドと空白で終えなければいけません。

1.2 Erlang の基礎をいくつか

  • 整数を 10 進以外で表現したい場合は、数字を基数#値の形で書く
10> 2#101010.
42
11> 8#0677.
447
12> 16#AE.
174

変化できない変数

1> One.
* 1: variable 'One' is unbound
2> One = 1.
1
3> Un = Uno = One = 1.
1
4> Two = One + One.
2
5> Two = 2.
2
6> Two = Two + 1.
** exception error: no match of right hand side value 3
9> two = 2.
** exception error: no match of right hand side value 2

two という単語は小文字から始まっているのでエラーになっています。

変数名は 大文字 で始めないとエラーになる

シェルでテストをしていて、変数に間違った値を保存してしまった場合は、関数 f(Variable). を使って変数を「消す」ことができます。

アトム

アトムは小文字から始まる一単語ですが、ほかにもアトムを作る方法があります。

1> atom.
atom
2> atoms_rule.
atoms_rule
3> atoms_rule@erlang. atoms_rule@erlang
4> 'Atoms can be cheated!'. 'Atoms can be cheated!'
5> atom = 'atom'.
atom

ブール代数と比較演算子

  • ブール代数
1> true and false.
false
2> false or true.
true
3> true xor false.
true
4> not false.
true
5> not (true and true).
false
6> 5 =:= 5.
true
7> 1 =:= 0.
false
8> 1 =/= 0.
true
9> 5 =:= 5.0.
false
10> 5 == 5.0.
true
11> 5 /= 5.0.
false

他の比較演算子には<(より小さい)、>(より大きい)、>=(以上)、=<(以下)が あります。最後の演算子は(私が思うに)左右逆...

  • =< に気をつける
    • >=
    • =<

Erlangではどんなものでもすべての型と足し算はできませんが、比較はできます。

14> 0 == false.
false
15> 1 < false.
true
>>> 0 == False
True
>>> 1 < True
False

タプル

1> X = 10, Y = 4.
4
2> Point = {X, Y}.
{10,4}
3> Point = {4, 5}.
{4,5}
4> {X, Y} = Point.
{4,5}
5> X.
4
6> {X, _} = Point.
{4,5}
7> {_, _} = {4, 5}.
{4,5}
8> {_, _} = {4, 5, 6}.
** exception error: no match of right hand side value {4,5,6}
2> PreciseTemperature = {celsius, 23.213}.
{celsius,23.213}
3> {kelvin, T} = PreciseTemperature.
** exception error: no match of right hand side value {celsius,23.213}
4> {celsius, T} = PreciseTemperature.
{celsius,23.213}
  • タグ付きタプル
    • アトムを 1 つめの要素に含むタプル
12> {point, {X, Y}}.
{point,{4,5}}

リスト

1> [1, 2, 3, {numbers, [4,5,6]}, 5.34, atom].
[1,2,3,{numbers,[4,5,6]},5.34,atom]
2> [97, 98, 99].
"abc"
3> [97, 98, 99, 4, 5, 6].
[97,98,99,4,5,6]
4> [233].
"é"

Erlang はリストの中の数字のうち、一つでも文字として表示できないものがあると、数字のリストとして数字を表示するのです!

  • リストを結合するには ++ 演算子。その反対は--で要素をリストから削除。
5> [1,2,3] ++ [4,5].
[1,2,3,4,5]
6> [1,2,3,4,5] -- [1,2,3].
[4,5]
7> [2,4,2] -- [2,4].
[2]
8> [2,4,2] -- [2,4,2].
[]
  • ++ と--のどちらも右結合。右から左に実行されていく。
9> [1,2,3] -- [1,2] -- [3].
[3]
10> [1,2,3] -- [1,2] -- [2].
[2,3]
11> [1,2] -- [3].
[1,2]
12> [1,2,3] -- [1,2].
[3]
13> [1,2] -- [2].
[1]
14> [1,2,3] -- [1].
[2,3]
  • リストの最初の要素は ‌head‌、残りの要素は ‌tail‌
11> hd([1,2,3,4]).
1
12> tl([1,2,3,4]).
[2,3,4]
13> List = [2,3,4].
[2,3,4]
14> NewList = [1 | List].
[1,2,3,4]
15> [Head | Tail] = NewList.
[1,2,3,4]
16> Head.
1
17> Tail.
[2,3,4]
18> [NewHead | NewTail] = Tail.
[2,3,4]
19> NewHead.
2
20> NewTail.
[3,4]
20> [1 | []].
[1]
21> [2 | [1 | []]].
[2,1]
22> [3 | [2 | [1 | []]]].
[3,2,1]
  • 全部等価
[a, b, c, d]
[a, b, c, d | []]
[a, b | [c, d]]
[a, b | [c | [d]]]
[a | [b | [c | [d]]]]
[a | [b | [c | [d | []]]]]

ややこしいがなんとなくわかった

リスト内包表記

リスト内包表記は集合記法からアイデアをもらっています。

  • {2n : n ∈ L}
1> [2*N || N <- [1,2,3,4]].
[2,4,6,8]

数学的記法と Erlang の記法を比べると、たいした違いはありません。波括弧({}) が角括弧([])になったり、コロン(:)が 2 つのパイプ(||)になっています。また ∈ という記号は矢印(<-)に置き換わっています。

python だとこう?

> [2*n for n in [1,2,3,4]]
[2,4,6,8]
  • ブール値を返す演算子を使っいリスト内包表記表記に条件を追加することもできる
2> [X || X <- [1,2,3,4,5,6,7,8,9,10], X rem 2 =:= 0].
[2,4,6,8,10]

python だとこう?

> [x for x in [1,2,3,4,5,6,7,8,9,10] if x % 2 == 0]
[2, 4, 6, 8, 10]
  • 〔パターン〕 <- 〔リスト〕の部分は 生成式

    • [2*N || N <- [1,2,3,4]]
    • Nがパターン、[1,2,3,4] がリスト
  • リストない表記は生成式を一つ以上持てる

5> [X+Y || X <- [1,2], Y <- [3,4]].
[4,5,5,6]

(1+3、1+4、2+3、2+4 )

  • 生成式がパターンマッチと組み合わせることでフィルタとして動作
6> Weather = [{toronto, rain}, {montreal, storms}, {london, fog},
6>             {paris, sun}, {boston, fog}, {vancouver, snow}].
[{toronto,rain},
  {montreal,storms},
  {london,fog},
  {paris,sun},
  {boston,fog},
  {vancouver,snow}]
7> FoggyPlaces = [X || {X, fog} <- Weather].
[london,boston]

バイナリデータを扱う

ビット構文

    • 使える値は integer、float、binary、bytes(binaryの短縮表現)、bitstring、bits(bitstringの短縮表現)、utf8、utf16、utf32 何も指定していなければ integer と推定
  • 符号付き
    • 使える値は signed と unsigned。デフォルトは unsigned。
    • integer のときだけパターンマッチに関係
  • エンディアン
    • big、little、native。デフォルトはbig
    • エンディアンは integer、utf16、utf32、float のときだけ関係
  • ユニット
    • unit:Integer のように書く
    • 各セグメントのサイズ
    • 1 から 256 の範囲で書くことができる
    • デフォルトでbitstring、float、bitstring では 1 ビットに、binary では 8 ビットに設定 されている
    • utf8、utf16、utf32 ではユニットを必要としない。
    • ユニットを〔サイズ〕に掛けるとセグメントが占めるビット数になり、これは 8 で割り切れる数でなければいけない。
10> <<X1/unsigned>> = <<-44>>.
<<"Ô">>
11> X1.
212
12> <<X2/signed>> = <<-44>>.
<<"Ô">>
13> X2.
-44
14> <<X2/integer-signed-little>> = <<-44>>.
<<"Ô">>
15> X2.
-44
16> <<N:8/unit:1>> = <<72>>.
<<"H">>
17> N.
72
18> <<N/integer>> = <<72>>.
<<"H">>
19> <<Y:4/little-unit:8>> = <<72,0,0,0>>.
<<72,0,0,0>>
20> Y.
72

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

Erlang には標準のバイナリ演算(左右ビットシフト、バイナリの and、or、xor、 not)もあります。関数bsl(Bit Shift Left、左ビットシフト)、bsr(Bit Shift Right、 右ビットシフト)、band、bor、bxor、bnot を使ってください。

2#00100 = 2#00010 bsl 1.
2#00001 = 2#00010 bsr 1.
2#10101 = 2#10001 bor 2#00101.
<<SourcePort:16, DestinationPort:16, AckNumber:32,
    DataOffset:4, _Reserved:4, Flags:8, WindowSize:16,
    CheckSum: 16, UrgentPointer:16,
    Payload/binary>> = SomeBinary.

バイナリ文字列

バイナリ文字列は<<"this is a binary string!">>のような構文を使います。

バイナリ内包表記

  • 基本的にはリスト内包表記と同様の表現
1> << <<X>> || <<X>> <= <<1,2,3,4,5>>, X rem 2 == 0>>.
<<2,4>>

通常のリスト内包表記との唯一の違いは、<-が<=になり、リスト([])の代わりに バイナリ(<<>>)になることです。

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>>
3> RGB = [ {R, G, B} || <<R:8,G:8,B:8>> <= Pixels ].
[{213,45,132},{64,76,32},{76,0,0},{234,32,15}]
4> << <<R:8,G:8,B:8>> || {R, G, B} <- RGB >>.
<<213,45,132,64,76,32,76,0,0,234,32,15>>
5> << <<Bin>> || Bin <- [<<3,7,5,4,7>>] >>.
** exception error: bad argument
6> << <<Bin/binary>> || Bin <- [<<3,7,5,4,7>>] >>.
<<3,7,5,4,7>>

デフォルトでは Erlang は、あなたがバイナリへ代入、あるいはバイナリから抽出 しようとしている値は数値(符号なし、8 ビット)だと推定します

  • バイナリ内包表記をバイナリ生成器として使える
7> << <<(X+1)/integer>> || <<X>> <= <<3,7,5,4,7>> >>.
<<4,8,6,5,8>>

この場合、Erlang はデフォルトで整数型と推定するので、型を integer とするの は余計です。

感想メモ

  • 技術書の1章って斜め読みしがちだけどこれはしっかり読まないとハマりどころになりそうな気がする。
  • 最初さらっと読んだ時は頭に入らなかったけどコードをシェルで動かしてみてたら理解できてきた気がする
  • バイナリデータあたりは理解できてない...
  • 第2章に続く(予定)