牌語備忘録 -pygo

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

牌語備忘録 -pygo

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

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

第3章 関数の構文

3.1 パターンマッチ

function(Args)
    if X then
〔式〕
else if Y then
〔式〕 else〔式〕

ではなく

function(X) ->
    〔式〕;
function(Y) ->
    〔式〕;
function(_) ->
    〔式〕.

と書く

  • それぞれの function 宣言が 関数節
  • 関数節は ; で区切られ、 関数宣言 でまとめられる。

ちょっと凝ったパターンマッチ

-module(functions).
-compile(export_all). % Replace with -export() later, for sanity's sake!

head([H|_]) -> H.
second([_,X|_]) -> X.
1> c(functions).
{ok, functions}
2> functions:head([1,2,3,4]).
1
3> functions:second([1,2,3,4]).
2

束縛する変数

  • 束縛されている変数に値を与えようとすると、新しい値が束縛されている値と同じでない限り 、エラーが発生します。
    valid_time({Date = {Y,M,D}, Time = {H,Min,S}}) ->
        io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n",[Date,Y,M,D]),
        io:format("The time tuple (~p) indicates: ~p:~p:~p.~n", [Time,H,Min,S]);
    valid_time(_) ->
        io:format("Stop feeding me wrong data!~n").
4> c(functions).
{ok, functions}
5> functions:valid_time({{2013,12,12},{09,04,43}}).
 The Date tuple ({2013,9,6}) says today is: 2013/9/6,
 The time tuple ({9,4,43}) indicates: 9:4:43.
ok
6> functions:valid_time({{2013,09,06},{09,04}}).
 Stop feeding me wrong data!
ok
  • この関数は、タプルが{{A,B,C},{D,E,F}}の形をしている限り、値として文字列でもアトムでもなんでも受け付けてしまう

3.2 ガードだ、ガード!

  • ガードは、パターンマッチの表現力を高めるために 関数のヘッドに書ける追加の節
old_enough(X) when X >= 16 ->
    true;
old_enough(_) ->
    false.
  • ガード式の基本的なルールは、成功時に true を返さなければいけない
  • もし false を返すか、例外を投げるなら、ガードは失敗

複数条件の場合

right_age(X) when X >= 16, X =< 104 ->
    true;
right_age(_) ->
    false.

カンマ(,)は andalso 演算子と同じように振 る舞い、セミコロン(;)は orelse のように振る舞う

wrong_age(X) when X < 16; X > 104 ->
    true;
wrong_age(_) ->
    false.

3.3 If ってなんだ?!

  • if 節はガードのように振る舞い、ガードと同じような構文
  • 関数節の先頭の外側で使う
  • if節はガードパターンと呼ばれている
  • 他の言語で見てきた if とは異なる
-module(what_the_if).
-export([heh_fine/0]).

heh_fine() ->
    if 1 =:= 1 ->
        works
    end,
    if 1 =:= 2; 1 =:= 1 ->
        works
    end,
    if1 =:= 2, 1 =:= 1 ->
        fails
    end.
1> c(what_the_if).
./what_the_if.erl:12: Warning: no clause will ever match
./what_the_if.erl:12: Warning: the guard for this clause evaluates to 'false'
{ok,what_the_if}
2> what_the_if:heh_fine().
** exception error: no true branch found when evaluating an if expression in function what_the_if:heh_fine/0
oh_god(N) ->
    if N =:= 2 -> might_succeed;
        true -> always_does %% This is Erlang's if's 'else!'
    end.
3> c(what_the_if).
./what_the_if.erl:12: Warning: no clause will ever match
./what_the_if.erl:12: Warning: the guard for this clause evaluates to 'false' {ok,what_the_if}
4> what_the_if:oh_god(2).
might_succeed
5> what_the_if:oh_god(3).
always_does

わかりやすく置き換える例
これを

if X > Y -> a()
 ; true -> b()
end

if X > Y -> a()
 ; X < Y -> b()
 ; true -> c()
end

こう置き換える

if X > Y -> a()
 ; X =< Y -> b()
end

if X > Y -> a()
 ; X < Y -> b()
 ; X == Y -> c()
end

3.4 もしも...の場合(In Case ... of)

  • if式がガードのようなものだとしたら、case ... of式は関数のヘッド全体のようなもの
insert(X,[]) ->
    [X];
insert(X,Set) ->
    case lists:member(X,Set) of
        true -> Set;
        false -> [X|Set]
    end.
beach(Temperature) ->
    case Temperature of
        {celsius, N} when N >= 20, N =< 45 ->
            'favorable';
        {kelvin, N} when N >= 293, N =< 318 ->
            'scientifically favorable';
        {fahrenheit, N} when N >= 68, N =< 113 ->
            'favorable in the US';
        _ ->
            'avoid beach'
    end.
beachf({celsius, N}) when N >= 20, N =< 45 ->
    'favorable';
...
beachf(_) ->

3.5 どれを使えばいいの?

  • if、case... of、関数という3つのうち、どれを使う かは、わりと答えるのが難しい質問
  • 明らかな違いの 1 つは、1 つ以上の引数 が評価される時
    • function(A,B) -> ...はAとBに対してガードと値のパターンマッチを持てる
    • case 式では
case {A,B} of
    〔パターン〕〔ガード〕-> ...
end.

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

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

第2章 モジュール

2.1 モジュールとは

  • モジュールは 1 つの名前で 1 つのファイルにまとめられた関数群

  • モジュール内に定義された他のすべての関数は、呼び出す形

    • 〔モジュール名〕:〔関数名〕(〔引数〕)
1> erlang:element(2, {a,b,c}).
b
2> element(2, {a,b,c}).
b
3> lists:seq(1,4).
[1,2,3,4]
4> seq(1,4).
** exception error: undefined shell command seq/2

2.2 モジュールを作る

  • モジュールで宣言できる2つ
    • 関数
    • 属性

属性は、モジュール名や外部に公 開する関数、コードの作者名などといった、モジュール自身の メタデータです。

  • すべてのモジュール属性は「-〔属性名〕(〔値〕).」

module 属性で定義したモジュール名とファイル名は一致しなければいけないこ とに注意してください。

  • -export([〔関数1〕/〔アリティ〕,〔関数2〕/〔アリティ〕, ..., 〔関数 N〕/〔アリティ〕]).
  • 関数の アリティ というのは引数の数
    • 例:add/2 や add/3 という形式

Erlang コミュニティでの規約では、モジュール全般にかかわるコメント(モジュールの用 途、ライセンスなど)やモジュール内の区切り(public なコード、private なコード、ヘル パー関数など)に関してはパーセント記号 3 つ(%%%)を使うことになっています。パーセ ント記号 2 つ(%%)の場合は、行コメントとして用いて、インデントは周りのインデントに 合わせます。パーセント記号 1 つ(%)は行末コメントに用いられます。

  • -import(〔モジュール〕, [〔関数1〕/〔アリティ〕,〔関数2〕/〔アリティ〕, ..., 〔関数 N〕/〔アリティ〕]).

useless.erl

-module(useless).
-export([add/2, hello/0, greet_and_add_two/1]).
add(A,B) ->
    A + B.
%% Shows greetings.
%% io:format/1 is the standard function used to output text.
hello() ->
    io:format("Hello, world!~n").
greet_and_add_two(X) ->
    hello(),
add(X,2).

2.3 コードをコンパイルする

  • コマンドライン
    • $ erlc〔フラグ〕file.erl
  • シェル内またはモジュール内
    • compile:file(〔ファイル名〕)
  • シェル
    • c()
  • シェルでディレクトリ移動
1> cd("/path/to/where/you/saved/the-module/").
"Path Name to the directory you are in"
ok
3> useless:add(7,2).
9
4> useless:hello().
Hello, world!
ok
5> useless:greet_and_add_two(-3).
Hello, world!
-1
6> useless:not_a_real_function().
** exception error: undefined function useless:not_a_real_function/0
  • Erlangの関数や式は 常に 何かを返さなければいけない。

コンパイラオプション

よく使うフラグ

  • -debug_info
  • -{outdir,〔ディレクトリ〕}
  • -export_all
  • -{d,〔マクロ〕}、 または -{d,〔マクロ〕,〔値〕}

コンパイル

7> compile:file(useless, [debug_info, export_all]).
{ok,useless}
8> c(useless, [debug_info, export_all]).
{ok,useless}

2.4 マクロを宣言する

  • Erlang のマクロは短い関数と定数の定義に使われる
  • コードが仮想マシン用にコンパイルされる前に置き換えられる
  • マジックバリューを避けるために主に使われる
  • マクロの定義
    • -define(〔MACRO〕, 〔値〕). -?〔MACRO〕 として使える
  • ある数字から別の数字を引く簡単なマクロの例
    • -define(sub(X,Y), X-Y).
  • 事前定義されたマクロの例
    • ?MODULE:現在のモジュール名のアトムに置換される
    • ?FILE:ファイル名の文字列に置換される
    • ?LINE:マクロが置かれた行番号に置換される
  • コード内で特定のマクロが宣言されているかどうかを確認・他のマクロを定義しているかどうか確認できる
    • -ifdef(〔MACRO〕).、-else.、-endif. という属性を使う
-ifdef(DEBUGMODE).
-define(DEBUG(S), io:format("dbg: "++S)).
-else.
-define(DEBUG(S), ok).
-endif.
  • テストマクロが定義されている場合にのみ存在するテストを定義する例
-ifdef(TEST).
my_test_function() ->
    run_some_tests().
-endif.

2.5 モジュールについてもっと詳しく

メタデータ

循環参照