Chapter3

Exercise3.1: Evaluating Expression

ここいらはお茶の子さいさいですな〜。

sum(N, N) -> N;
sum(N, M) when N < M -> M + sum(N, M-1);
sum(_N, _M) -> throw({error, {range_error}}).
Exercise3.2: Creating Lists

正順と逆順のリストを作る方法
いくらでも作り方はあるんだろうけど、正順の方は末尾再帰で、逆順の方はダイレクト再帰で。

create_acc(0, Xs) -> Xs;
create_acc(N, Xs) -> create_acc(N-1, [N|Xs]).
create(M) when (M >= 1) and is_integer(M) -> 
        create_acc(M, []).

reverse_create(0) -> [];
reverse_create(M) when (M >= 1) and is_integer(M) -> [M | create(M-1)].
Exercise3.3: Side Effects

リストを順に出力する関数を作れ、と。

% リストを出力
print_num_acc([]) -> true;
print_num_acc([H|T]) -> 
        io:format("Number:~p~n", [H]),
        print_num_acc(T).
print_num(N) ->
        print_num_acc(create(N)).

% 奇数の数字のみ出力
print_even_num_acc([]) -> true;
print_even_num_acc([H|T]) -> 
        case H rem 2 == 0 of 
                true -> io:format("Number:~p~n", [H]);
                false -> odd
        end,
        print_even_num_acc(T).
print_even_num(N) ->
        print_even_num_acc(create(N)).
Exercise3.4: Database Handling Using Lists

Erlang初心者なので、listsを使えばいい、と言われても即座に反応できなかったりする。
ここは、単にリストで。

-module(db).
-export([new/0, destroy/1, write/3, delete/2, read/2, match/2]).

% db:new/0
new() -> [].

% db:destroy/1
destroy(_) -> ok.

% db:write/3
write(Key, Element, Db) -> [{Key, Element} | delete(Key, Db)].

% db:delete/2
delete(Key, Db) -> delete_db(Key, Db).
delete_db(_, []) -> [];
delete_db(Key, [H|T]) ->
        case H of 
                {Key, _Element} -> delete_db(Key, T);
                _Other -> [H | delete_db(Key, T)]
        end.

% db:read/2
read(Key, Db) -> read_db(Key, Db).
read_db(_, []) -> {error, instance};
read_db(Key, [H|T]) ->
        case H of
                {Key, Element} -> {ok, Element};
                _Other -> read_db(Key, T)
        end.

% db:match/2
match(Element, Db) -> match_db(Element, Db).
match_db(_, []) -> [];
match_db(Element, [H|T]) ->
        case H of
                {Key, Element} -> [Key | match_db(Element, T)];
                _Other -> match_db(Element, T)
        end.
Exercise3.5: Manipulating Lists

SICPな人はお茶の子さいさい(ぼくは、よく怪しくなる)

%%% (1) filter
filter([], _) -> [];
filter([H|T], N) when H =< N ->
        [H | filter(T, N)];
filter([_|T], N) ->
        filter(T, N).

%%% (2) reverse
reverse_acc([], Xs) -> Xs;
reverse_acc([H|T], Xs) -> reverse_acc(T, [H|Xs]).
reverse(L) -> reverse_acc(L, []).

%%% (3) concatenate
append([], Ys) -> Ys;
append(Xs, []) -> Xs;
append([H|T], Ys) -> [H | append(T, Ys)].
concatenate([L]) -> L;
concatenate([H1, H2 | T]) -> 
        concatenate([append(H1, H2) | T]).

%%% (4) flatten
flatten([]) -> [];
flatten([H|T]) -> append(flatten(H), flatten(T));
flatten(X) -> [X].
Exercise3.6: Sorting Lists

ここは、id:Ehrenにならって、ちゃんとテスト付きで(というか、ソース泥棒という噂も)。

%% Author: mizutomo
%% Created: 2009/12/07
%% Description: Quicksort & Mergesort
-module('ex3_6').

%% Include Files
-include_lib("eunit/include/eunit.hrl").

%% Exported Functions
-export([qsort/1, msort/1]).

>%% Test Functions
my_sort_test_() ->
        [
         ?_assertEqual(qsort([1,3,2]),[1,2,3]),
         ?_assertEqual(qsort([3,2,0,1,5,8,4,2,2,7]),[0,1,2,2,2,3,4,5,7,8]),
         ?_assertEqual(msort([1,3,2]),[1,2,3]),
         ?_assertEqual(msort([3,2,0,1,5,8,4,2,2,7]),[0,1,2,2,2,3,4,5,7,8])
        ].

%% ----------------------------------------------------------
%% Func: qsort/1
%% Desc: Quick Sort
%% Returns: sorted list
%% ----------------------------------------------------------
select(_, [], _) -> [];
select(X, [H|T], 'lessthan') when H =< X -> [H | select(X, T, 'lessthan')];
select(X, [H|T], 'lessthan') when H > X  -> select(X, T, 'lessthan');
select(X, [H|T], 'largerthan') when H > X -> [H | select(X, T, 'largerthan')];
select(X, [H|T], 'largerthan') when H =< X -> select(X, T, 'largerthan').
%qsort([]) -> [];
%qsort([X|Xs]) ->
%       qsort(select(X, Xs, 'lessthan')) ++ [X] ++ qsort(select(X, Xs, 'largerthan')).
qsort([]) -> [];
qsort([X|Xs]) ->
        qsort([Y || Y <- Xs, Y =< X]) ++ [X] ++ qsort([Y || Y <- Xs, Y > X]).
         
         
%% ----------------------------------------------------------
%% Func: msort/1
%% Desc: Merge Sort
%% Returns: sorted list
%% ----------------------------------------------------------
make_sorted_list(Xs, []) -> Xs;
make_sorted_list([], Ys) -> Ys;
make_sorted_list([X|Xs], [Y|Ys]) ->
        case X =< Y of
                true  -> [X | make_sorted_list(Xs, [Y|Ys])];
                false -> [Y | make_sorted_list([X|Xs], Ys)]
        end.
msort(Xs) when length(Xs) == 1 -> Xs;
msort(Xs) ->
        {Left, Right} = lists:split(length(Xs) div 2, Xs),
        make_sorted_list(msort(Left), msort(Right)).


残りの問題は力尽きた。というか、最近Twitterで時間を潰しすぎてるようなキモス。
とりあえず、3-8は今後のためにも役に立ちそうなので、勉強会後にでもちゃんとやるようにしましょう。