体重が52.7kg
危機的状況ではないだろうか?
サンタクロース問題。
43行ではないけど、Erlang で。
なんだか random が怪しい?
after 0 でトナカイを優先しないといけなかったですね。
-module(santa).
-compile(export_all).
-record(stat, {'こびと'=[], 'トナカイ'=[]}).
start() ->
register('サンタ', spawn_link(?MODULE, 'サンタ', [#stat{}])),
lists:foreach(fun(N) -> spawn_link(?MODULE, 'こびと_init', [N]) end,
lists:seq(1, 10)),
lists:foreach(fun(N) -> spawn_link(?MODULE, 'トナカイ_init', [N]) end,
lists:seq(1, 9)).
'サンタ'(#stat{'トナカイ'=X}=Stat) when length(X) == 9 ->
'サンタ働く'("おもちゃくばり", X),
'サンタ寝てる'(Stat#stat{'トナカイ'=[]});
'サンタ'(#stat{'こびと'=X}=Stat) when length(X) == 3 ->
'サンタ働く'("おもちゃ会議", X),
'サンタ寝てる'(Stat#stat{'こびと'=[]});
'サンタ'(Stat) ->
'サンタ寝てる'(Stat).
'サンタ働く'(What, Who) ->
io:format("~s開始...", [What]),
sleep(10),
io:format("終了。~n"),
lists:foreach(fun(A) -> A ! 'おつかれさま。' end, Who).
'サンタ寝てる'(Stat) ->
receive
{'トナカイ', N, X} ->
io:format("トナカイ~bが来た。~n", [N]),
'サンタ'(Stat#stat{'トナカイ'=[X|Stat#stat.'トナカイ']})
after 0 ->
receive
{'こびと', N, X} ->
io:format("こびと~bが来た。~n", [N]),
'サンタ'(Stat#stat{'こびと'=[X|Stat#stat.'こびと']})
end
end.
'こびと_init'(N) ->
random:seed(N, N*N, N*N*N*N),
'こびと'(N).
'こびと'(N) ->
sleep(30),
'サンタ' ! {'こびと', N, self()},
receive
'おつかれさま。' ->
'こびと'(N)
end.
'トナカイ_init'(N) ->
random:seed(N*N*N, N*N*N, N),
'トナカイ'(N).
'トナカイ'(N) ->
sleep(30),
'サンタ' ! {'トナカイ', N, self()},
receive
'おつかれさま。' ->
'トナカイ'(N)
end.
sleep(N) ->
X = random:uniform(N),
timer:sleep(X*1000).
関数は fun my_module:my_fun/1 のような型で使えるが、オペレータはこれができない。
でも、Erlang ではシングルクウォートで囲めば任意の関数名(atom)を作れるので、次のように '+' とかいう関数を定義してみる。
すると、lists:foldl(fun ope:'+'/2, 0, lists:seq(1, 100)). みたいなことができるけど、嬉しいかなぁ?
-module(ope).
-export(['+'/2, '-'/2, '*'/2, '/'/2, test/0]).
'+'(A, B) ->
A + B.
'-'(A, B) ->
A - B.
'*'(A, B) ->
A * B.
'/'(A, B) ->
A / B.
test() ->
lists:foldl(fun ope:'+'/2, 0, lists:seq(1, 100)).
定義されていない関数が呼ばれたときのハンドラです。
定義されていない関数が呼ばれた場合 error_handler:undefined_function/3 が呼ばれます。
error_handler:undefined_function/3 は呼ばれた関数のモジュールをロードし、ロードできればその関数をもう一度呼んでみる、とうような動きをします。
error_handler:undefined_function/3 をユーザ定義の関数で置き換えることができます。
マニュアルには危険なので要注意、とうようなことが書かれていますが、この機能でモジュールの継承のようなものができないでしょうか。
-module(my_module).
-compile(export_all).
undefined_function(my_module, Func, Args) ->
io:format("no sush funciton!! ~p:~p(~p)~n", [my_module, Func, Args]);
undefined_function(Module, Func, Args) ->
io:format("original handler...~n"),
error_handler:undefined_function(Module, Func, Args).
test() ->
process_flag(error_handler, my_module),
my_module:foo("Hello"),
xxxx:yyyy(zzzz).
文字列をコンパイルする方法です。
erl_scan:tokens で1文ずつスキャン。
erl_parse:parse_form で1文ずつパース。
compile:forms でモジュール単位でコンパイル。
code:load_binary でコンパイルしたものをロードです。
改行コードは \n にしておかないとだめです。
-module(compile_string).
-export([compile/1, test/0]).
compile(FormsStr) ->
Forms = mk_forms(lists:flatten(FormsStr)),
{ok, M, B} = compile:forms(Forms),
{module, M} = code:load_binary(M, atom_to_list(M), B),
M.
mk_forms(String) ->
mk_forms(String, []).
mk_forms([], Acc) ->
lists:reverse(Acc);
mk_forms(S, Acc) ->
{done, {ok, Tokens, _Line}, Rest} = erl_scan:tokens([], S, 0),
{ok, Parsed} = erl_parse:parse_form(Tokens),
mk_forms(Rest, [Parsed|Acc]).
test() ->
S = "-module(fib).
-export([fib/1]).
fib(1) -> 1;
fib(2) -> 1;
fib(N) -> fib(N-1) + fib(N-2).
",
compile(S),
fib:fib(10). % コンパイルした関数を呼出す。