Erlang をはじめよう その5
前回 - mog project: Getting Started with Erlang pt.4 の続き
CHAPTER 9: Exceptions, Errors, and Debugging
try .. catch の基本形
1 2 3 4 5 | > try math:sqrt(-1) of > Result -> Result > catch > error: Error -> {error, Error} > end. |
1 2 3 4 | > try math:sqrt(2) > catch > error: Error -> {error, Error} > end. % ok |
1 2 3 4 | > try math:sqrt(-2) > catch > error: Error -> {error, Error} > end. |
1 2 3 4 5 6 7 8 | > try > X = -2, > math:sqrt(X) > of > Result -> Result > catch > error: Error -> {error, Error} > end. |
after 節の指定
1 2 3 4 5 6 7 8 9 | > F = fun(X) -> try math:sqrt(X) > catch > error: Error -> {error, Error} > after > io:format("AFTER CODE~n") > end > end. > F(2). > F(-2). |
例外の送出
エラーと例外を区別することができる。
1 2 3 4 5 6 | > throw(my_exception). > try throw(my_exception) > catch > error: Error -> {found, Error}; > throw: Exception -> {caught, Exception} > end. |
メッセージのロギング
1 2 3 4 5 | > error_logger:info_msg("information~n"). > error_logger:warning_msg("warning~n"). > error_logger:error_msg("error~n"). > error_logger:info_msg("~p~n", []). > error_logger:info_report("~p~n", []). % フォーマットエラーの場合の挙動が異なる |
ログファイルへの書き込み
カレントディレクトリ配下に test.log というファイルを作成。
1 2 3 | > error_logger:logfile({open, "test.log"}). > error_logger:info_msg("information"). > error_logger:logfile(close). |
GUI でのデバッグ
debug_info オプションを付けてコンパイルする必要がある。
1 2 | > c(shop, [debug_info]). > debugger:start(). |
- [GUI操作] Module -> Interrupt... -> デバッグ対象のモジュールを Choose
1 | > Pid1 = spawn(async_shop,async_shop,[]). |
- [GUI操作] Break -> Line Break でブレイクポイントを設置。
1 | > Pid1 ! {apple, 3}. |
ステップ実行や、変数の値を確認できた。
コンソールでのデバッグ
- 送受信メッセージのトレース
1234> dbg:tracer().
> Pid1 = spawn(async_shop,async_shop,[]).
> dbg:p(Pid1,m).
> Pid1 ! {apple, 3}.
- 関数呼び出しのトレース
fact.erl 1234567-module(fact).
-export([factorial/1]).
factorial(N) -> factorial(1, N, 1).
factorial(Current, N, Result) when Current =< N -> factorial(Current + 1, N, Result * Current);
factorial(Current, N, Result) -> Result.
12345> c(fact).
> dbg:tracer().
> dbg:p(all, c).
> dbg:tpl(fact, factorial, []).
> fact:factorial(4).
CHAPTER10: Storing Structured Data
レコード
レコードとは、固定長のデータ構造であり、名前でアクセスすることができるフィールドからなる。
Cの構造体のようなもの。
Erlang におけるレコードはコンパイル時の機能であって、VMに固有の型があるわけではない。
- レコードの基本操作
複数のモジュールで共有できるように、レコード定義は個別のファイル(拡張子hrl)に記述するのがよいらしい。
records.hrl 1-record(person, {name, age=20, phone}).
1234567891011> rr("records.hrl").
> Person1=#person{}.
> Person2=#person{name="Alice", age=16}.
> Person3=#person{name="Bob", phone="123-4567", age=35}.
> #person{phone=P, name=N} = Person3.
> {P, N}.
> Person3 = Person3#person{name="Charlie"}. % error
> Person4 = Person3#person{name="Charlie"}.
> rf().
> #person{}.
> Person1.
- モジュール内でレコードを利用する
person.erl 1234567-module(person).
-export([rename/2]).
-include("records.hrl").
rename(#person{name=Name} = Person, NewName) ->
io:format("Changed name: ~s -> ~s~n", [Name, NewName]),
Person#person{name=NewName}.
1234> c(person).
> rr("records.hrl").
> P = #person{name="Alice", age=16, phone="123-4567"}.
> person:rename(P, "Bob").
Erlang Term Storage (ETS)
Erlang 付属の KVS (key/value store)。
- テーブルの作成
users.erl 12345678910-module(users).
-export([setup/0]).
-include("records.hrl").
setup() ->
Table = ets:new(users, [named_table, {keypos, #person.name}]),
ets:insert(users, #person{ name="Alice", age=16, phone="123-4567"}),
ets:insert(users, #person{ name="Bob", age=35, phone="000-0000"}),
ets:insert(users, #person{ name="Charlie", age=66, phone="111-1111"}),
ets:info(Table).
123456> c(users).
> users:setup(). % size を確認
> rr("records.hrl").
> ets:tab2list(users).
> tv:start(). % GUI が起動
> ets:i().
このような GUI でレコードの内容を確認できる。
- レコードの読み込みと更新
1234567> users:setup().
> rr("records.hrl").
> ets:lookup(users, "Alice").
> ets:lookup(users, "Carol").
> Alice = hd(ets:lookup(users, "Alice")).
> ets:insert(users, Alice#person{age=17}).
> ets:lookup(users, "Alice").
Mnesia
分散、並列機能を完全に有した Erlang 付属のDBMS。発音は「エムニージア」でよさそうだ。
- スキーマ、テーブルの作成
users.erl 12345678910111213141516-module(users).
-export([setup/0]).
-include("records.hrl").
setup() ->
mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(person, [{attributes, record_info(fields, person)}]),
F = fun() ->
mnesia:write(#person{ name="Alice", age=16, phone="123-4567"}),
mnesia:write(#person{ name="Bob", age=35, phone="000-0000"}),
mnesia:write(#person{ name="Charlie", age=66, phone="111-1111"})
end,
mnesia:transaction(F).
12345> c(users).
> rr("records.hrl").
> users:setup().
> mnesia:table_info(person, all).
> tv:start().
- クエリの実行
123456789> mnesia:transaction(fun() -> mnesia:read(person, "Alice") end).
> mnesia:transaction(fun() -> qlc:e(qlc:q( [X || X <- mnesia:table(person)])) end).
> mnesia:transaction(fun() -> qlc:e(qlc:q(
[X || X <- mnesia:table(person), X#person.age < 40]
)) end).
> mnesia:transaction(fun() -> qlc:e(qlc:q(
[ {X#person.name, X#person.age} ||
X <- mnesia:table(person), X#person.age < 40]
)) end).
References
0 件のコメント:
コメントを投稿