「すごいErlangゆかいに学ぼう!」1章

すごいErlangゆかいに学ぼう!」という本をジャケ買いしてしまったので、ちょとずつ読むことにしました。読み途中の本はいろいろあるのだけど、こういう本は旬な時期にノリで読んだほうがいいですし。

というわけで、読書メモを載せていきます。些細な疑問を書きとめるように努めます(後で解決した時楽しいから)

今日は1章のリスト内包表記の説明で立ち止まったところがあったので、ひとまずそこまで。

イントロダクション

イントロダクションは、参照透過の話から。

アクターモデルというのを理解してコードを書くのが鍵となるらしい。

Erlangの話題で出てくるOTPとは、Open Telecom Platformのこと。Online Transaction Processingだと思ってた。

何千もの軽量プロセスを起動できるけど、だからといってそうするべきではないという話が書いてある。

インストール

手元のMacErlangをインストール。

$ brew install erlang
==> Installing dependencies for erlang: openssl, unixodbc, jpeg, libpng, 
==> Installing erlang dependency: openssl
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/openssl-1.0
######################################################################## 100.0%
==> Pouring openssl-1.0.1h.mavericks.bottle.tar.gz
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /usr/local/etc/openssl/certs

and run
  /usr/local/opt/openssl/bin/c_rehash

This formula is keg-only, so it was not symlinked into /usr/local.

Mac OS X already provides this software and installing another version in
parallel can cause all kinds of trouble.

The OpenSSL provided by OS X is too old for some software.

Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:

    LDFLAGS:  -L/usr/local/opt/openssl/lib
    CPPFLAGS: -I/usr/local/opt/openssl/include

==> Summary
🍺  /usr/local/Cellar/openssl/1.0.1h: 429 files, 14M
==> Installing erlang dependency: unixodbc
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/unixodbc-2.
######################################################################## 100.0%
==> Pouring unixodbc-2.3.2.mavericks.bottle.tar.gz
🍺  /usr/local/Cellar/unixodbc/2.3.2: 31 files, 1012K
==> Installing erlang dependency: jpeg
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/jpeg-8d.mav
######################################################################## 100.0%
==> Pouring jpeg-8d.mavericks.bottle.2.tar.gz
🍺  /usr/local/Cellar/jpeg/8d: 18 files, 780K
==> Installing erlang dependency: libpng
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/libpng-1.6.
######################################################################## 100.0%
==> Pouring libpng-1.6.12.mavericks.bottle.tar.gz
🍺  /usr/local/Cellar/libpng/1.6.12: 17 files, 1.2M
==> Installing erlang dependency: libtiff
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/libtiff-4.0
######################################################################## 100.0%
==> Pouring libtiff-4.0.3.mavericks.bottle.tar.gz
🍺  /usr/local/Cellar/libtiff/4.0.3: 254 files, 3.8M
==> Installing erlang dependency: wxmac
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/wxmac-3.0.1
######################################################################## 100.0%
==> Pouring wxmac-3.0.1.mavericks.bottle.tar.gz
🍺  /usr/local/Cellar/wxmac/3.0.1: 777 files, 41M
==> Installing erlang
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/erlang-17.0
######################################################################## 100.0%
==> Pouring erlang-17.0.mavericks.bottle.tar.gz
==> Caveats
Man pages can be found in:
  /usr/local/opt/erlang/lib/erlang/man

Access them with `erl -man`, or add this directory to MANPATH.
==> Summary
🍺  /usr/local/Cellar/erlang/17.0: 7355 files, 280M

数値型

算術演算では、整数と浮動小数点を区別しない。

整数÷整数がしたいときはdev、余りが欲しいとき(Javaでいうと%)はremを使う。

基数#値の形で、2〜36進数の10進表現が得られる。36てすごいな。

変数は大文字から始める。

技術的には、変数はアンダースコア(_)から始めてもかまいません。しかし規約としては、アンダースコアは用がない変数だけに使うことになっています。

用がないってどういうこと? 変数を与えずに関数を呼び出す時とかかな。→後でタプルの項で説明があった。アンダースコアは、「使わずに捨ててしまう値がくる場所」に置くらしい。

=演算子で変数に値を1回だけ代入できる。すでに値が入っている場合、同じ値であれば、代入する「ふり」(!)ができる。

右辺と左辺が違う値のとき、exception errorが出る。

変数に入れた値はf(変数名)で消すことができる。f()で全部消える。(ただしテストかシェルの中でだけ)

アトム

文字列リテラルみたいなものかな? →違いました。

GCの対象ではないので、アトムを動的に大量生成するアトムアタックみたいなのが起こりうるかもしれないという話。

ブール代数

and と or を使う。短絡評価したいときは、andalso と orelse を使う。

比較演算子

整数と浮動小数点を異なるものとして扱うには、=:= と =/=を 使う。気にせずに比較する時は == と /= を使う。

「以上」は「>=」だけど、「以下」は「=<」と記述する。非対称なので注意。

違う型同士の値に算術演算子を適用するとエラーになるが、比較演算子は適用できる。trueやfalseはアトムであってブール値ではない。numberはatomよりも小さい値として言語内で定義されている。そのため、1 < false と 1 < true の結果は、どちらもtrueになる。

タプル

タプルでのパターンマッチは要素数が同じときに成功する。

捨てられる値にアンダースコアを使った例。

81> Point = {1, 2}.
{1,2}
82> {X, _} = Point.
{1,2}
83> X.
1
84> _.
* 1: variable '_' is unbound
85> Y.
* 1: variable 'Y' is unbound
86> {X, Y} = Point.
{1,2}
87> Y.
2

「タグ付きタプル」とは、1つ目の要素がアトムであるタプルのこと。

タプルは要素として他のタプルを含むことができる。

リスト

文字列はリストなので、文字列として評価可能なリストは、文字列になる。文字列として評価できないリストは、数字のまま表示される。これはすごい。これはひどい

104> [97,98,99,0].
[97,98,99,0]
105> [97,98,99].  
"abc"

うぉぅ。。。まあ、割り切って進む方向で。バイナリ文字列というのが後で出てくるらしいし。

リスト結合は++を使う。リストから要素を削除するのは--を使う。要素の削除では、前から順に見て、見つけた要素を1つだけ削除するらしい。

108> [2, 4, 2] -- [2, 4].
[2]
109> [2, 4, 2] -- [2, 4, 2].
[]
110> [2, 4, 2, 4]--[2, 4].
[2,4]

リストの最初の要素がheadで、hd関数で取り出せる。以降の要素がtailで、tl関数で取り出せる。パターンマッチでheadとtailを分離できる。

120> [H | T] = [1, 2, 3, 4].
[1,2,3,4]
121> H.
1
122> T.
[2,3,4]

本に載っていた、リストに新しいheadを追加する方法。

130> List = [2, 3, 4].
[2,3,4]
131> NewList = [1 | List].
[1,2,3,4]

上のコードは、次のコードとは違うのかな? 結果は一緒だけども。

132> NewListEx = [1] ++ List.
[1,2,3,4]

p.14の記述。

(略)(ヒント:これらは全部等価です)。

[a, b, c, d]
[a, b, c, d | []]
[a, b | [c, d]]
[a, b | [c | [d]]]
[a | [b | [c | [d]]]]
[a | [b | [c | [d | []]]]]

3つ目と4つ目で、cons演算子の前に項目を2つ以上書いているけれど、これは普通にありなの? それともこれは再帰的定義の説明のために書いているのかな?

その前のページで、

どんなリストも[(項1) | [(項2) | [ … | [(項N)]]]]という形で作れます。

とあったから、リストの中に書かれたconsは、headとtailを分けるものだと思い込んでいた。

[a, b]

は、

[a | [b]]

と同じだからいいのかな。(?)

リスト内包表記

p.15に次のような2つのサンプルコードがある。

1つ目。1〜10の集合から偶数の集合だけを取り出す。

2> [X || X <- [1,2,3,4,5,6,7,8,9,10], X rem 2 =:= 0].
[2,4,6,8,10]

→分かる。

2つ目。税込み(7%)3ドルから10ドルの間に収まる料理の価格を取り出す。

たとえば、レストランを経営しているとします。お客が入って、メニューを見て、税込み(たとえば7%)で$3から$10の間に収まるような料理の価格をすべて見たいといった場合です。

3> RestaurantMenu = [{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}]
4> [{Item, Price*1.07} || {Item, Price} <- RestaurantMenu, Price >= 3, Price =< 10].
[{steak,6.409300000000001},{beer,4.2693},{poutine,3.745}]

→分からない。

もし行番号4のコードが次のようになっていれば、理解できる。

4> [{Item, Price*1.07} || {Item, Price} <- RestaurantMenu, Price*1.07 >= 3, Price*1.07 =< 10].

元のコードでは、「||」の右側の条件に「Price >= 3, Price =< 10」と書いただけで、「税込み(たとえば7%)で$3から$10の間に収まるような料理の価格」を得ているという。税率は「||」の左側にしか書かれてないのに、元の集合から結果の集合を取り出す際に、左側に書かれたものも評価されるのだろうか?

分かりやすくするために、税抜きなら10ドルに収まるが、税込みなら10ドルを超えるワインを追加してみる。

7> Menu = [{steak, 5.99}, {beer, 3.99}, {poutine, 3.50}, {kitten, 20.99}, {water, 0.00}, {wine, 9.99}].
[{steak,5.99},
 {beer,3.99},
 {poutine,3.5},
 {kitten,20.99},
 {water,0.0},
 {wine,9.99}]
8> [{Item, Price*1.07} || {Item, Price} <- Menu, Price >= 3, Price =< 10].  
 [{steak,6.409300000000001},
 {beer,4.2693},
 {poutine,3.745},
 {wine,10.689300000000001}]

あれ? 元のコードを実行すると、税込み価格が10ドルを超えるワインが取れてしまっている。

9> [{Item, Price*1.07} || {Item, Price} <- Menu, Price*1.07 >= 3, Price*1.07 =< 10].
[{steak,6.409300000000001},{beer,4.2693},{poutine,3.745}]

条件で比較するPriceに税率を与えてみたら、今度は結果にワインが出現しない。やはり、税込み価格が3ドルから10ドルに収まるという条件を、「||」の右側に書く必要がある。

説明文とサンプルコードに齟齬があっただけだった。

今日はここまで :)