Language detail: Erlang

Coverage: 42.08%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

IPv4アドレスのマスクの変換 (Nested Flatten)

Scala(#9133)をErlangに移植しました。 効率はともかく、例外処理をしているので・・・

関数の仕様は、Erlang的で、成功時は {ok,****} のようなタプルが返ります。失敗時はok以外のアトム。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
-module(netmask).
-export([numbits_of/1,from_numbits/1,test/0]).

numbits_of(StrMask) -> 
    try
        {ok,Mask} = inet_parse:address(StrMask) ,
        {Class,MaskByte} = case Mask of
                        {255,255,255,X} -> {24,X};
                        {255,255,  X,0} -> {16,X};
                        {255,  X,  0,0} -> { 8,X};
                        _ -> throw("bad mask")
                        end,
        {ok,
        case MaskByte of
            (256-  1)-> 8;
            (256-  2)-> 7;
            (256-  4)-> 6;
            (256-  8)-> 5;
            (256- 16)-> 4;
            (256- 32)-> 3;
            (256- 64)-> 2;
            (256-128)-> 1;
            0        -> 0
        end + Class }% <--- result
    catch
        throw:E -> {thrown,E};
        exit :E -> {exited,E};
        error:E -> {error ,E}
    end.

from_numbits(Numbits)->
    try
        {Class,Maskbits} = 
                        case Numbits of
                            N when N>=24 -> {24,N-24} ;
                            N when N>=16 -> {16,N-16} ;
                            N when N>= 8 -> { 8,N- 8} 
                        end ,
        Maskbyte = 
                case Maskbits of 
                    8 -> (256-  1) ;
                    7 -> (256-  2) ;
                    6 -> (256-  4) ;
                    5 -> (256-  8) ;
                    4 -> (256- 16) ;
                    3 -> (256- 32) ;
                    2 -> (256- 64) ;
                    1 -> (256-128) ;
                    0 -> 0
                end ,
        %
        {ok , 
        case Class of
            24 -> inet_parse:ntoa( {255,255,255,Maskbyte} ) ;
            16 -> inet_parse:ntoa( {255,255,Maskbyte  ,0} ) ;
            8  -> inet_parse:ntoa( {255,Maskbyte    ,0,0} ) 
        end }% <--- result
    catch
        throw:E -> {thrown,E};
        exit :E -> {exited,E};
        error:E -> {error ,E}
    end.

test()->
    lists:foreach(fun(I)->
                    {ok , M} = from_numbits(I),
                    {ok , N} = numbits_of(M),
                    io:format("Numbits=~p , Mask=~p , Result=~p~n",[I,M,(I==N)])
                  end , lists:seq(8,31) ).
ファイルサイズの取得 (Nested Flatten)

Erlang初投稿です。よろしくお願いします。 とりあえず、システムコールを呼ぶ回数を1回にしました。 erlide(Eclipse)で確認しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
-module(file_size).
-export([file_size/1]).

-include_lib("kernel/include/file.hrl").

file_size(Name) ->
    try file:read_file_info(Name) of
        {ok,Fileinfo} ->
            case Fileinfo#file_info.type of
                regular ->
                    io:format("~B~n",[Fileinfo#file_info.size]);
                _ -> ok % except file
            end;
        _ -> ok % cannot get infomation
    catch
        _ -> ok % exception
    end.

file_size.erlで保存し、以下のように実行します。:

$ erl -noshell -s file_size file_size file_size.erl -s init stop
189

存在しないファイル(例えばdummy.txtとする)を指定すると、何も表示されません。:

$ erl -noshell -s file_size file_size dummy.txt -s init stop
1
2
3
4
5
6
7
8
-module(file_size).
-export([file_size/1]).

file_size(Name) ->
    case filelib:is_file(Name) of
        false -> ok;
        true -> io:format("~B~n", [filelib:file_size(Name)])
    end.
例外処理 (Nested Flatten)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-module(exception).
-export([exception/0]).

f() -> throw("exception").

exception() ->
    X =  try f()
    catch
        throw : Y -> "catch : " ++ Y
    end,
    io:format(X).
疑似並行処理 (Nested Flatten)

Erlang のプレーンな例は、他の方が解答されていましたので、あえて lists ライブラリを積極的に使ったパターンを投稿してみます。 ミソは、終了メッセージの選択受信かな?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
-module(doukaku215).
-author('cooldaemon@gmail.com').
-export([run/0]).

run() ->
  Pid = self(),
  lists:foreach(
    fun (CPid) -> receive {CPid, finish} -> ok end end,
    lists:map(
      fun (Cs) -> spawn(fun () ->
        lists:foreach(fun (C) -> io:fwrite("~s", [[C]]) end, Cs),
        Pid ! {self(), finish}
      end) end,
      lists:map(fun (N) -> lists:seq(N, N+8) end, [$1, $A])
    )
  ).
以下のようにして実行します。

erlc para.erl 
erl -noshell -s para para -s init stop
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-module(para).
-export([para/0]).

proc(Pid, []) -> Pid ! void;
proc(Pid, [Chr | Str]) ->
    io:format("~s", [[Chr]]),
    proc(Pid, Str).

para() ->
    Pid = self(),
    spawn(fun() -> proc(Pid, "0123456789") end),
    spawn(fun() -> proc(Pid, "ABCDEFGHIJ") end),
    receive _ -> receive _ -> void end end.
タブ区切りデータの処理 (Nested Flatten)
実行方法:
$ cat hoge.txt
ID	Surname	Forename	Age
1	Sato	Hanako	17
0	Suzuki	Taro	18

$ erlc doukaku7723.erl
$ erl -noshell -s doukaku7723 main hoge.txt -s init stop
ID	Forename	Surname	Age
0	Taro	Suzuki	19
1	Hanako	Sato	18
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
-module(doukaku7723).
-export([main/1]).

main(Filename) ->
    {ok, Bin} = file:read_file(Filename),
    A1 = string:tokens(binary_to_list(Bin), "\r\n"),
    [H | T] = lists:map(curry(flip(fun string:tokens/2), "\t"), A1),
    A2 = lists:map(fun swap23inc4/1, T),
    A3 = lists:sort(fun([E1|_], [E2|_]) -> list_to_integer(E1) < list_to_integer(E2) end, A2),
    A4 = lists:map(func_comp(fun lists:concat/1, curry(fun intersperse/2, "\t")), [swap23(H) | A3]),
    A5 = lists:concat(intersperse("\r\n", A4)),
    io:format("~s~n", [A5]).

swap23([A,B,C,D | Rest]) -> [A,C,B,D|Rest].
swap23inc4([A,B,C,D | Rest]) -> [A,C,B,integer_to_list(1+list_to_integer(D)) | Rest].

intersperse(_, []) -> [];
intersperse(_, [X]) -> [X];
intersperse(Sep, [X | XS]) -> [X, Sep | intersperse(Sep, XS)].
curry(F, A) -> fun(B) -> F(A, B) end.
flip(F) -> fun(A, B) -> F(B, A) end.
func_comp(F, G) -> fun(X) -> F(G(X)) end.
echoクライアント (Nested Flatten)

echoのプロトコル(RFC862)に詳しくないのですが、サーバ側からデータの終わり(eofなど)が返ってこないようなので、タイムアウト(10秒)を設定してみました(汗

送信したデータと比較して、同じならcloseする条件もつけました。

escriptが利用可能な環境であれば、以下のようにコマンドラインから実行可能です。

$ ./スクリプト名 localhost 7 < testfile > newfile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env escript
main([Hostname, Port])->
        Str = loop(io:get_line(standard_io,''), []),
        Res = gen_tcp:connect(Hostname,
                        list_to_integer(Port),
                        [binary, {packet, 0}]),
        case Res of
                {ok, Socket} ->
                        ok = gen_tcp:send(Socket, Str),
                        receive_data(Socket, [], lists:flatten(Str));
                {error, Why} -> io:format("error ~p~n", [Why]), exit(eError)
        end.

receive_data(Socket, _Original, _Original) ->
                gen_tcp:close(Socket);
receive_data(Socket, SoFar, Original) ->
        receive
                {tcp, Socket, Bin} ->
                        Lines = binary_to_list(Bin),
                        io:format("~s", [Lines]),
                        receive_data(Socket, lists:flatten(SoFar ++ [Lines]), Original);
                {tcp_closed, Socket} ->
                        ok
        after 10000 ->
                gen_tcp:close(Socket)
        end.

loop(eof, SoFar)->
    lists:reverse(SoFar);
loop(Data, SoFar) ->
    loop(io:get_line(''), [Data|SoFar]).
2^i * 3^j * 5^k なる整数 (Nested Flatten)

しらみつぶしに計算してからsortする方式ですが、その境界の目処はたてるようにしてみました。 http://en.wikipedia.org/wiki/Image:Regular_divisibility_lattice.svg の図を、3次元空間のある象限に存在する三角錐とみて、それを含む直方体の中の格子点を取り出します。最低でも、およそ5/6が無駄なデータなのですが、うまく三角錐の部分だけの格子点を巡回する順序を決めるアルゴリズムが思い浮かばなかったので、そのままにしてあります。

$ erlc スクリプトのファイル名

$ erl -noshell -s len main 100 -s init stop

として実行します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-module(len).
-export([main/1]).

main([N|_]) ->
        Limit = list_to_integer(atom_to_list(N)),
        Factor = math:pow(Limit * math:log(5) * math:log(2)/ (math:log(2) * math:log(3)), 1 / 3),
        L = lists:sort([round(math:pow(2, X)*math:pow(3,Y)*math:pow(5,Z)) ||
                 X <- lists:seq(0,round(1 + Factor * math:log(5) / math:log(2)) ),
                 Y <- lists:seq(0,round(1 + Factor * math:log(5) / math:log(3)) ),
                 Z <- lists:seq(0,round(1 + Factor))]),
        io:format("~p~n",[lists:sublist(L,Limit)]).
LL Golf Hole 8 - 横向きのピラミッドを作る (Nested Flatten)
実行するには

erlc pyramid.erl
erl -noshell -run pyramid main 自然数 -s init stop

としてください。
http://ja.doukaku.org/comment/7419/ とは違い、0 の場合エラーになります。
1
2
3
4
5
-module(pyramid).
-export([main/1]).

main([S])->N=list_to_integer(S),[io:format("~*c
",[N-abs(M),$*])||M<-lists:seq(1-N,N-1)].
#7419で投稿しましたが、push, popという関数名がそぐわない感じがしたので、
別のスタイルで書いてみました。
改行を含む文字列を前後両側に伸ばしていく感じです。
実行方法は#7419同様です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-module(pyramid).
-export([main/1]).

main([N])->
        Len=list_to_integer(atom_to_list(N)),
        s(Len,p(Len)).

s(0,_)->0;
s(1,S)->io:format("~s", [S]);
s(N,S)->s(N - 1, p(N - 1) ++ S ++ p(N - 1)).

p(0)-> [$\n];
p(N)-> "*" ++ p(N - 1).
実行するには、以下のようにコマンド入力します。
コマンドの引数として数値を与えています。
一応、0のケースも入れておきました。

erlc スクリプトファイル名
erl -noshell -s pyramid main 自然数 -s init stop

実行例
$ erl -noshell -s pyramid main 0 -s init stop

$ erl -noshell -s pyramid main 1 -s init stop
*

$ erl -noshell -s pyramid main 3 -s init stop
*
**
***
**
*
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
-module(pyramid).
-export([main/1]).

main([N])-> push(list_to_integer(atom_to_list(N)),[]).

push(0,_)->0;
push(1,L)->io:format("~s~n",[L ++ "*"]), pop(L ++ "*");
push(N,L)->io:format("~s~n",[L ++ "*"]), push(N - 1, L ++ "*").

pop("*")-> 0;
pop([_|L])-> io:format("~s~n",[L]), pop(L).
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)
実行する場合は以下のようにコマンドを実行します。
数値はコマンドの引数として与えます。

erlc ファイル名
erl -noshell -s kuraidori put 数値 -s init stop

実行例
$ erl -noshell -s kuraidori put 1234567890 -s init stop
1.2G
$ erl -noshell -s kuraidori put 12345678901234 -s init stop
12.3T
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
-module(kuraidori).
-export([put/1]).

put([S]) -> loop(list_to_integer(atom_to_list(S))," KMGTPEZY").

loop(S,[H|[]]) -> pr(S,H);
loop(S,[H|_]) when S < 1000 ->
        if
        is_integer(S) -> pri(S,H);
        true -> pr(S,H)
        end;
loop(S,[_|L]) -> loop(S / 1000, L).

pr(S,K) -> io:format("~.1f~s~n",[S,[K]]).
pri(S,K) -> io:format("~.10B~s~n",[S,[K]]).
倍数になる13進数 (Nested Flatten)
erl_evalと Erlang特有のN進法表記(N#M, 基数Nは36以下)を
使ってみたらどうだろうと思って書いてみました。
基数に上限があるので汎用性に欠けると思います。

プログラムを bai13.erl というファイル名で保存して、
$ erl -noshell -s bai13 getfirst -s init stop
のようにして起動します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
-module(bai13).
-export([getfirst/0]).

getfirst() ->
    loop(10).

loop(N) ->
    case (eval("13#" ++ integer_to_list(N) ++ ".") rem N) of
        0 -> io:format("~p~n",[N]);
        true -> loop(N + 1)
    end.

eval(Expr)->
    {ok, Tokens, _}=erl_scan:string(Expr),
    {ok,[Expression]} = erl_parse:parse_exprs(Tokens),
    {value, Ret,_} = erl_eval:expr(
        Expression ,erl_eval:bindings(erl_eval:new_bindings())
        ),
  Ret.
LL Golf Hole 6 - 10進数を2進数に基数変換する (Nested Flatten)
Erlangのインタプリタコマンドであるescriptで実行するとしたケースです。
その場合、コードの最初の行は無視されるので、コメント行となっています。

入力となる10進数は、標準入力から与えます。

実行例(スクリプトファイル名を t.erl とします)
$ escript  t.erl
2
10
$
1
2
%
main(_)->{V,_}=string:to_integer(io:get_line('')),io:format("~.2B~n",[V]).
LL Golf Hole 5 - 最上位の桁を数え上げる (Nested Flatten)
スクリプト内のリテラルとして、300という整数を与えています。

escript スクリプトのファイル名

として実行します。
この場合、最初のコメント行は必須です。
1
2
3
4
5
%
s(X,Y)when X < 10->erlang:display(Y);
s(X,Y)when X rem 10=:=0->s(X div 10,Y);
s(_,_)->0.
main(_)->[s(X,X)||X<-lists:seq(0,300)].
LL Golf Hole 3 - 13日の金曜日を数え上げる (Nested Flatten)
申し訳ありません、動かないコードを投稿してしまいました。
最初に投稿したものは、最初に空行が必要でした。
(escriptコマンドは、最初の行を無視するため)
最初の行をコメントとして、コードも多少短くしたものを再投稿いたします。

実行方法と結果は、以下のように、元記事と同様です。

escript スクリプトのファイル名
[{2009,2,13},
 {2009,3,13},
 {2009,11,13},
 {2010,8,13},
 {2011,5,13},
 {2012,1,13},
 {2012,4,13},
 {2012,7,13},
 {2013,9,13},
 {2013,12,13}]
10 days
1
2
3
4
%%
main(_)->M=[{X,Y,13}||{X,Y,13}<-a(date(),{2013,12,31}),calendar:day_of_the_week({X,Y,13})=:=5],io:format("~p~n~p days~n",[M,length(M)]).
a(X,X)->[X];
a(X,Y)->[X]++a(calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(X)+1),Y).
大元になる日付のリストは素直に1日ごとのものを生成しています。
escript ファイル名
として実行します。
実行結果例(2008/8/7に実行)
[{2009,2,13},
 {2009,3,13},
 {2009,11,13},
 {2010,8,13},
 {2011,5,13},
 {2012,1,13},
 {2012,4,13},
 {2012,7,13},
 {2013,9,13},
 {2013,12,13}]
10 days
1
2
3
4
5
6
7
8
main(_) ->
        L=a(date(),{2013,12,31}),
    M=[{X,Y,13} || {X,Y,13} <- L, calendar:day_of_the_week({X,Y,13}) =:= 5],
    io:format("~p~n~p days~n", [M, length(M)]).

a(X,X) -> [X];
a(X,Y) -> [X] ++ a(calendar:gregorian_days_to_date(
                 calendar:date_to_gregorian_days(X)+1),Y).
LL Golf Hole 2 - 文字列に含まれる単語の最初の文字を大文字にする (Nested Flatten)

Erlang 版を縮めてみました。

1
S=string,S:join([[S:to_upper(H)]++T||[H|T]<-S:tokens("LL day and night"," ")]," ").

Erlang 版を 1 文字削り損ねてました。

1
S=string,S:join([[S:to_upper(H)|T]||[H|T]<-S:tokens("LL day and night"," ")]," ").
next >>

Index

Feed

Other

Link

Pathtraq

loading...