February 9, 2010

An Interview with Leslie Lamport

Found nice blog article about the interview with Lamport.

Following is a also nice reading to know how he thinks what programmers should learn:

  • Lamport, L. 2009. Teaching concurrency. SIGACT News 40, 1 (Feb. 2009), 58-62. DOI= http://doi.acm.org/10.1145/1515698.1515713 

February 7, 2010

Paxos Algorithm Info

Projects using Paxos ( or related algorithm ):


Followings are nice references for Paxos:

In this paper, why Paxos is better than 2PC/3PC for distributed system is stated in very short space
  • Mejías, B., Högqvist, M., and Roy, P. V. 2008. Visualizing Transactional Algorithms for DHTs. In Proceedings of the 2008 Eighth international Conference on Peer-To-Peer Computing (September 08 - 11, 2008). P2P. IEEE Computer Society, Washington, DC, 79-80. DOI= http://dx.doi.org/10.1109/P2P.2008.48




Erlang Programming::Exercise 5-2:Swapping Handlers

not sure if this works...there seems to be a problem for this question. just only diff part.

swap_handlers(Name, OldHandler, NewHandler) ->
    call(Name, {swap_handler, OldHandler, NewHandler}).
    
handle_msg({swap_handler, OldHandler, NewHandler}, LoopData) ->
    case lists:keysearch(OldHandler, 1, LoopData) of
        false ->
            {{error, instance}, LoopData};
        {value, {OldHandler, Data}} ->
            Reply = {data, OldHandler:terminate(Data)},
            NewLoopData = [{NewHandler, NewHandler:init(Reply)}|LoopData],
            NewLoopData2 = lists:keydelete(OldHandler, 1, NewLoopData),
            {{swap_ok, Reply}, NewLoopData2}
    end;

Erlang Programming::Exercise 5-2:Changing the Frequency Server

I need to do my homework for school now...

-module(frequency).
-export([start/0, stop/0, allocate/0, deallocate/1, showlist/0]).
-export([init/0]).

start() ->
    register(frequency, spawn(frequency, init, [])).

init() ->
    Freq = {get_frequencies(), []},
    loop(Freq).

get_frequencies() -> generate_freq([]).

generate_freq([]) -> generate_freq([10]);
generate_freq([Freq|_] = FreqList ) when Freq >= 30 -> 
    lists:reverse(FreqList);
generate_freq([Freq|Rest]) -> 
    generate_freq([Freq + 1, Freq | Rest]).

stop()           -> call(stop).
allocate()       -> call(allocate).
deallocate(Freq) -> call({deallocate, Freq}).
showlist()       -> call(showlist).

call(Message) ->
    frequency ! {request, self(), Message},
    io:format("MODULE:[~w] LINE:[~w] Message:[~p]~n", [?MODULE, ?LINE, Message]),
    receive
        {reply, Reply} -> Reply
    end.

loop(Frequencies) ->
    receive
        {request, Pid, allocate} ->
            {_Free, Allocated} = Frequencies,
            Result = lists:filter(fun({_,X}) -> X =:= Pid end, Allocated), 
            if ( length(Result) < 3) ->       % allocate only when the process has less than
                                              % 3 frequencies allocated
                {NewFreq, Reply} = allocate(Frequencies, Pid),
                reply(Pid, Reply),
                loop(NewFreq);
            true ->
                reply(Pid, ng),
                loop(Frequencies)
            end;
        {request, Pid, {deallocate, Freq}} ->
            {Ret, NewFreq} = deallocate(Frequencies, {Pid, Freq}),
            if(Ret =:= ok) ->
                reply(Pid, ok);
            true ->
                reply(Pid, ng)
            end,
            loop(NewFreq);
        {request, Pid, stop} ->
            {_Free, Allocated} = Frequencies,
            if( length(Allocated) =:= 0 ) ->  % stop only when no freqs are allocated
                reply(Pid, ok);
            true ->
                reply(Pid, ng),
                loop(Frequencies)
            end;
        {request, Pid, showlist} ->
            {Free, Allocated} = Frequencies,
            Reply = io:format("Free:[~p] Allocated:[~p]~n", [Free, Allocated]),
            reply(Pid, Reply),
            loop(Frequencies);
        Other -> io:format("LINE:[~w] ~p~n", [?LINE, Other])
    end.

reply(Pid, Reply) ->
    Pid ! {reply, Reply}.

allocate({[], Allocated}, _Pid) ->
    {{[], Allocated}, {error, no_frequency}};
allocate({[Freq|Free], Allocated}, Pid) ->
    {{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}.

deallocate({Free, Allocated}, {Pid, Freq}) ->
    case lists:keysearch(Freq, 1, Allocated) of
        % no frequency to deallocate
        false                -> {ng, {Free, Allocated}};
        % ok to deallocate
        {value, {Freq, Pid}} -> NewAllocated = lists:keydelete(Freq, 1, Allocated),
                                {ok, {[Freq|Free], NewAllocated}};
        % ng to deallocate
        {value, {Freq, _}}   -> {ng, {Free, Allocated}}
    end.


Erlang Programming::Exercise 5-1:A Datavase Server

This pattern concept is invaluable.

-module(mydb).
-export([start/0, stop/0, write/2, delete/1, read/1, match/1]).
-export([init/0]).

start() ->
    register(mydb, spawn(mydb, init, [])).

init() ->
    loop([]).

stop()           -> call(stop).
write(Key, Data) -> call({write, Key, Data}).
delete(Key)      -> call({delete, Key}).
read(Key)        -> call({read, Key}).
match(Key)       -> call({match, Key}).


call(Msg) ->
    mydb ! {request, self(), Msg},
    receive
        {reply, Reply} -> Reply
    end.

loop(DataList) ->
    receive
        {request, Pid, stop} ->
            reply(Pid, {stop, DataList}),
            io:format("db end..");
        {request, Pid, {write, Key, Data}} ->
            reply(Pid, {write, ok}),
            loop([{Key, Data}|DataList]);
        {request, Pid, {delete, Key}} ->
            case lists:keysearch(Key, 1, DataList) of 
                false                -> reply(Pid,{error_delete, Key}),
                                        loop(DataList);
                {value, {Key, Data}} -> NewDataList = lists:keydelete(Key, 1, DataList), 
                                        reply(Pid, {delete, ok}),
                                        loop(NewDataList)
            end;
        {request, Pid, {read, Key}} ->
            case lists:keysearch(Key, 1, DataList) of 
                false                -> reply(Pid, {error_read, Key}),
                                        loop(DataList);
                {value, {Key, Data}} -> reply(Pid, {read, Data}), 
                                        loop(DataList)
            end;
        {request, Pid, {match, Data}} ->
            ResultList = extract_data(Data, DataList, []),
            reply(Pid, ResultList),
            loop(DataList)
    end.

reply(Pid, Reply) ->
    Pid ! {reply, Reply}.

extract_data(_Ele, [], A) -> A;
extract_data(Ele, [{Key,Ele}|Tail], A) -> extract_data(Ele, Tail, [Key|A]);
extract_data(Ele, [_Head|Tail], A) -> extract_data(Ele, Tail, A).


Erlang Programming::Exercise 4-2:The Process Ring

spawn and register are tricky..registered name and variable contents are, of course, different.

-module(ring).
-export([start/3, stop/0, start_ring/4, send/2]).
-export([loop/2]).

makelist(N) -> lists:map(fun(X) -> list_to_atom(integer_to_list(X)) end, makelist_acc(N,[])).

makelist_acc(0, List) -> List;
makelist_acc(N, List) -> makelist_acc(N-1, [N|List]).


start(N,M,Msg) ->
    Proclist = lists:reverse(makelist(N)),
    start_ring(N, M, Msg, Proclist).

stop() ->
    '1' ! stop.

start_ring(N,M,Msg,[This|[]]) ->
    Next = list_to_atom(integer_to_list(N)),
    register(This, spawn(?MODULE, loop, [Next,This])),
    Next ! {print, Msg, M};
start_ring(N,M,Msg,[This|Proclist]) ->
    Next = hd(Proclist),
    register(This, spawn(?MODULE, loop, [Next,This])),
    start_ring(N, M, Msg, Proclist).


loop(Next, This) ->
    receive
        {print, _, 0} ->
            io:format("Msg#:[Complete]!!!~n"),
            loop(Next, This);
        {print, Msg, M} ->
            io:format("Proc:[~p] Msg:[~p] Msg#:[~p]~n", [This, Msg, M]),
            if(This < Next) -> % means last process
                Msgnum = M - 1;
            true ->
                Msgnum = M
            end,
            Next ! {print, Msg, Msgnum},
            loop(Next, This);
        stop -> 
            io:format("Proc:[~p] Good bye.~n", [This]),
            try
                true = erlang:is_process_alive(whereis(Next)), 
                Next ! stop
            catch
                error:_ -> io:format("All Process terminated.~n")
            end;
        Other -> 
            io:format("error, received:[~p]~n", [Other]),
            loop(Next, This)
    end.


February 2, 2010

Review: 3 Types of Semaphore

I'm reviewing my class staff :).

There are 3 types of semaphore use.
1. Signal Semaphore
2. Mutex Semaphore
3. Counting Semaphore

Signal Semaphore is used to order the sequence of processing between processes or threads.Semantics is following:
1.init semaphoe value <- 0
2.P() in shoud-be-later part
3.V() in should-be-first part

next is the sample code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "semlib.h"


int main(void)
{
int sem_signal; // signal semaphoe

semop_init();

/* get semaphoe */
sem_signal = sem_get();

/* set the value of the semaphoe to 0 */
sem_init_value(sem_signal, 0);

if(fork() == 0){
/* Child */
sem_lock(sem_signal);
/* ------- this part is after the parent -----------*/
printf("I'm a child, shoule be after my parent.\n");
/* -------------------------------------------------*/
exit(0);
}
/* ------- from this part is before the child ----------- */
printf("I'm a parent, should be the first\n");
/* ------- to this part---------------------------------- */
sem_unlock(sem_signal);

/* remove the semaphoe */
sem_remove(sem_signal);

return 0;
}



Mutex Semaphoe if used to make a critical section:
1. init semaphore value <-1
2. P() at the start of C.S in each code segment
3. V() at the end of C.S in each code segment

next is the sample code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include "semlib.h"

#define NUM_CHILDREN 10
#define REPEAT_TIME 3

int main(int argc, char *argv[])
{
int sem_mutex;
int shmid;
int *mysm;
char mysm_l[256];
int ret_val, i, j, shm_val=0;

semop_init();
sem_mutex = sem_get();
sem_init_value(sem_mutex, 1);

fprintf(stderr, "Starting the main routine\n");
if ((shmid = shmget(IPC_PRIVATE,1,0777)) < 0) {
perror("Could not create shared memory");
exit(-1);
}else{
fprintf(stderr, "Shared memory segment created\n");
}
/* attach shmemory and initialize it */
if(( mysm = (int *)shmat(shmid,NULL,0)) < 0) {
perror("Cannot attach shared memory in parent");
exit(-1);
}
*mysm = 0;

/* generate chileren and operate against shared memory */
for(i=0;i<NUM_CHILDREN;i++){
if (fork() == 0){
fprintf(stderr,"Starting Child %d\n", i);
if(( mysm = (int *)shmat(shmid,NULL,0)) < 0) {
perror("Cannot attach shared memory in child");
exit(-1);
}
fprintf(stderr, "Child[%d] attached shared memory\n", i);
/* read shmem,
* sleep 1 sec,
* increment local variable by 1,
* display it,
* write back it to shmem
* sleep 1 sec
*/
for(j=0;j<REPEAT_TIME;j++){

sleep(1);

/* lock the critical section*/
sem_lock(sem_mutex);
(*mysm)++;
sem_unlock(sem_mutex);

sprintf(mysm_l, "child[%d] value[%d]\n", i, *mysm);
fputs(mysm_l, stderr);
sleep(1);
}

fprintf(stderr, "This is Child %d exiting\n", i);
exit(0);
}
}

/* main, wait all children */
fprintf(stderr, "This is the main program again\n");
i=NUM_CHILDREN;
while(i--){
wait(0);
}

/* display the value of share memory */
sprintf(mysm_l, "parent[%d] value[%d]\n", getpid(), *mysm);
fputs(mysm_l, stderr);

/* detatch shared memory */
if((ret_val = shmctl(shmid, IPC_RMID,0)) < 0 ) {
perror("Cannot destroy shared memory segment--do manually!\n");
exit(-1);
}
fprintf(stderr, "This is the main program exiting\n");

/* remove the semaphoe */
sem_remove(sem_mutex);


return 0;
}


Counting Semaphore is used to allocate a certain number of resources:
1. init semaphoe value <- # of resource
2. P() to allocate the available resource
3. V() to deallocate the available resource

so, in order to manage queue, we need 3 semaphore, 1st is mutex, 2nd is to maintain upper bound number of the queue, 3rd is to maintain lower bound number of the queue...

next is the sample code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <pthread.h>
#include "semlib.h"

#define REPEAT_TIME 100

int sem_up_limit; /* counting semaphe */
int sem_low_limit; /* counting semaphe */
int sem_mutex; /* mutex semaphe */

int queue[10]; /* queue */
int start_pos = 0; /* start position of the queue */
int end_pos =0; /* end position of the queue */

void th_enqueue(void *arg)
{
int i;
for(i=0; i<REPEAT_TIME ;i++){
sem_lock(sem_up_limit); /* block if queue if full */
sem_lock(sem_mutex);

queue[start_pos] = i;
start_pos++;
start_pos = start_pos%(sizeof(queue)/sizeof(queue[0]));

sem_unlock(sem_mutex);
sem_unlock(sem_low_limit); /* increment the # of available value */
}
}
void th_dequeue(void *arg)
{
int i;
for(i=0; i<REPEAT_TIME ;i++){
sem_lock(sem_low_limit); /* block if no value */
sem_lock(sem_mutex);

printf("dequeued:%d\n", queue[end_pos]);
queue[end_pos] = 0; /* when dequeue, just clear it */
end_pos++;
end_pos = end_pos% (sizeof(queue)/sizeof(queue[0]));

sem_unlock(sem_mutex);
sem_unlock(sem_up_limit); /* increment the # of available space */
}
}

int main(void)
{

pthread_t tid_enq, tid_deq;
int arg_enq_th, arg_deq_th;
int retvalue;

semop_init();

/* get semaphore */
sem_mutex = sem_get();
sleep(1);
sem_up_limit = sem_get();
sleep(1);
sem_low_limit = sem_get();

/* for mutex, first come, first served */
sem_init_value(sem_mutex, 1);

/* for lower bound check( if queue is empty, block )
* put to the queue : V
* get from the queue: P
*/
sem_init_value(sem_low_limit, 0);

/*
* for upper bound check( if queue is full, block )
* put to the queue : P
* get from the queue: V
*/
sem_init_value(sem_up_limit, (sizeof(queue)/sizeof(queue[0])));


/* create enqueue/dequeue threads */
if ((retvalue=pthread_create(&tid_enq,NULL, (void *)th_enqueue, (void *)&arg_enq_th)) < 0){
perror("Can't create enqueue thread");
exit(-1);
}
if ((retvalue=pthread_create(&tid_deq,NULL, (void *)th_dequeue, (void *)&arg_deq_th)) < 0){
perror("Can't create dequeue thread");
exit(-1);
}
/* wait threads here */
pthread_join(tid_enq, NULL);
pthread_join(tid_deq, NULL);

/* remove the semaphore */
sem_remove(sem_mutex);
sem_remove(sem_low_limit);
sem_remove(sem_up_limit);

return 0;
}


and, next is my semaphore functions used in sample:

struct sembuf sem_p;
struct sembuf sem_v;


union {
int val;
struct semid_ds *buf;
ushort *array;
}sem_arg;

void semop_init()
{
/* lock operation */
sem_p.sem_num = 0;
sem_p.sem_op = -1;
sem_p.sem_flg = 0;

/* unlock operation */
sem_v.sem_num = 0;
sem_v.sem_op = 1;
sem_v.sem_flg = 0;

}

int sem_get(void)
{
int sem_id;
int key = time(0);

/* semaphoe create and initialize */
if ((sem_id = semget(key,1,0777|IPC_CREAT)) < 0) {
perror("Could not create semaphore");
exit(-1);
}
fprintf(stderr, "Semaphores created\n");

return sem_id;

}

void sem_remove(int sem_id)
{
/* remove semaphoe */
if(semctl(sem_id, IPC_RMID,0) < 0 ) {
perror("Cannot destroy semaphoe --do manually!\n");
exit(-1);
}
}

void sem_init_value(int sem_id, int init_value)
{

int semval;

/* set the initial value of the semaphe to 1 */
sem_arg.val = init_value;
if(semctl(sem_id, 0, SETVAL, sem_arg) < 0){
perror("Could not initialize semaphore");
exit(-1);
}
semval = semctl(sem_id,0,GETVAL,sem_arg);
printf("Semaphoe value is :%d\n", semval);

}

int sem_get_value(int sem_id)
{
int semval;
if( (semval = semctl(sem_id,0,GETVAL,sem_arg)) == -1 ){
perror("Could not get semaphore value");
exit(-1);
}
return semval;

}

void sem_unlock(int sem_id)
{
if(semop(sem_id,&sem_v,1) < 0) {
perror("Can't do a V call in main\n");
exit(-1);
}
}

void sem_lock(int sem_id)
{
if(semop(sem_id,&sem_p,1) < 0) {
perror("Can't do a P call in main\n");
exit(-1);
}
}






February 1, 2010

Erlang Programming::Exercise 3-8

I was almost giving up for this exercise, but found nice sample code below:
http://d.hatena.ne.jp/vostok92/20090818/1250602559

So I read above code over and over, then wrote it(however almost same).

-module(comp).
-export([parse/1]).

parse(String) ->
{Term, []} = term(String),
Term.

term([$( | Rest]) -> % term ::= "(" exp ")"
{Term, [$)|Rest2]} = expr(Rest),
{Term, Rest2};
term([$~ | Rest]) -> % term ::= "~" exp
{Term, Rest2} = term(Rest),
{{uminus, Term}, Rest2};
% term ::= number
term([Num|_] = Rest) when $0 =< Num, Num =< $9 ->
{Num2, Rest2} = num(Rest,[]),
{{num, Num2}, Rest2}.


expr(Rest) -> % expr ::= term Op term
{Term_res1, [Op|Rest2]} = term(Rest),
if ((Op =:= $+) or (Op =:= $-) or (Op =:= $*) or (Op =:= $/)) ->
Opc = case Op of
$+ -> plus;
$- -> minus;
$* -> mult;
$/ -> divi
end,
{Term_res2, Rest3} = term(Rest2),
{{Opc, Term_res1, Term_res2}, Rest3};
true -> term(Rest) % expr ::= term
end.

num([Num|Rest],A) ->
if( ($0 =< Num) and (Num =< $9) ) ->
num(Rest,[Num|A]);
true->
{lists:reverse(A), [Num|Rest]}
end;
num([],A) ->
{lists:reverse(A), []}.






January 30, 2010

Erlang Programming::Exercise 3-6

quick sort and merge sort. it took more time than expected, and still need to improve.

-module(mysort).
-export([qsort/1, msort/1, split/1]).

qsort([]) -> [];
qsort([P|L]) ->
Small = [X || X <- L, X < P],
Large = [X || X <- L, X >= P],
qsort(Small) ++ [P] ++ qsort(Large).

comp(E1, E2) when E1 < E2 -> true;
comp(_, _) -> false.

split(L) ->
split(L,L,[]).
split([],L1,L2) ->
{L1,L2};
split(L1,[],L2) ->
{L1,L2};
split([H1|R1],[H2|R2],L2) ->
if (length([H1|R2]) - length(L2) =< 1) ->
{[H2|R2], lists:reverse(L2)};
true ->
split(R1, R2, [H1|L2])
end.


merge([], L2) -> L2;
merge(L1, []) -> L1;
merge(L1, L2) ->
case comp(hd(L1),hd(L2)) of
true -> [hd(L1)| merge(tl(L1), L2)];
false -> [hd(L2)| merge(L1, tl(L2))]
end.

msort([]) -> [];
msort([H]) -> [H];
msort(L1) ->
{H1, H2} = split(L1),
merge(msort(H1), msort(H2)).





January 29, 2010

Erlang Programming::Exercise 3-5

flatten was difficult for me.

-module(mylist).
-export([filter/2, reverse/1, concatenate/1, flatten/1, in_concatenate_elements/2, in_concatenate/2, in_reverse/2]).

in_filter([], _, A) -> lists:reverse(A);
in_filter([H|T], Int, A) when H =< Int -> in_filter(T, Int, [H|A]);
in_filter([H|T], Int, A) when H > Int -> in_filter(T, Int, A).

filter([], _) -> [];
filter(List, Int) -> in_filter(List, Int, []).

in_reverse([], L) -> L;
in_reverse([H|L], A) -> in_reverse(L, [H|A]);
in_reverse(Element,[]) -> Element.

reverse([]) -> [];
reverse(L) -> in_reverse(L,[]).


in_concatenate_elements([], A) -> A;
in_concatenate_elements([[]|T], A) -> in_concatenate_elements(T, A);
in_concatenate_elements([H|T], A) -> in_concatenate_elements(T, [H|A]);
in_concatenate_elements(Element, []) -> Element; % in case Element is not a list
in_concatenate_elements(Element, A ) -> [Element|A]. % in case Element is not a list

in_concatenate([], A) -> A;
in_concatenate([List|Tail], A) -> B = in_concatenate_elements(List, A),
in_concatenate(Tail, B).

concatenate([]) -> [];
concatenate(List) -> lists:reverse(in_concatenate(List, [])).

in_flatten([], List) -> lists:reverse(List);
in_flatten([H|T], A) when is_list(H) -> in_flatten(concatenate([flatten(H),T]),A);
in_flatten([H|T], A) -> in_flatten(T, [H|A]).


flatten([]) -> [];
flatten(L) -> in_flatten(L, []).





Erlang Programming::Exercise 3-4

I'm not sure if I understood the problem correctly, but at least it was fun.

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

get_id() ->
{Mega, Sec, Micro} = now(),
integer_to_list(Mega) ++ integer_to_list(Sec) ++ integer_to_list(Micro).

in_get_listoftaple(Db) ->
case get(Db) of
undefined -> undefined;
[] -> undefined;
L -> L
end.

in_delete(Key, [{Key,_}|T], A) -> in_delete(Key,T, A);
in_delete(Key, [{H,V}|T], A) -> in_delete(Key, T, [{H,V}|A]);
in_delete(_, [], A) -> A.

new() ->
Db = get_id(),
put(Db,[]),
Db.

read(Key, Db) ->
case in_get_listoftaple(Db) of
undefined -> {error, instance};
L -> {_, {Key, Element}} = lists:keysearch(Key, 1, L), {ok, Element}
end.

write(Key, Element, Db) ->
NewDb = get_id(),
case get(Db) of
undefined -> undefined;
[] -> put(NewDb, [{Key, Element}]),
erase(Db),
NewDb;
L -> put(NewDb, [{Key, Element}|L]),
erase(Db),
NewDb
end.

extract_key(_Ele, [], A) -> A;
extract_key(Ele, [{Key,Ele}|Tail], A) -> extract_key(Ele, Tail, [Key|A]);
extract_key(Ele, [_Head|Tail], A) -> extract_key(Ele, Tail, A).

match(Ele, Db) ->
case get(Db) of
undefined -> undefined;
[] -> [];
L -> extract_key(Ele, L, [])
end.

delete(Key, Db) ->
NewDb = get_id(),
case in_get_listoftaple(Db) of
undefined -> put(NewDb,[]), NewDb;
L -> A = in_delete(Key, L, []), put(NewDb, A), io:format("~p~n",[A]),NewDb
end.

destroy(Db) ->
case erase(Db) of
undefined -> false;
Db -> ok
end.




January 27, 2010

Erlang::Tail Recursion

From p.64 of Erlang programming, it says "In general, a function f is tail-recursive when the only calls to f occur as the last expression (i.e., tail) in the bodies of the clauses of f."
so, following is not tail-recursive:

sum([]) -> 0;
sum([H|T]) -> H + sum(T).

tail-recursive version is the following:
sum([]) -> 0;
sum(L) -> sum_acc(A,L).

sum_acc(A,[]) -> A;
sum_acc(A,[H|T]) -> sum_acc(A+H, T).


In practice, it seems that wheather tail-recursive or not does not affect the performance a lot in the current version of Erlang as we can check in Eight Myths of Erlang Performance. But it's still important to understand it, I guess.

Maybe, when I write it in C, the difference is clearer and it's easier to understand why tail-recursive function is more efficient.Here, we can see that tail-recursive function can be modified easily so that it does not consume stack.
#include <stdio.h>

void bump(int *i, int index)
{
/*
if(index < 0){
return;
}else{
(*i)++;
i++;
return bump(i, index -1);
}
*/
while(index >= 0){
i[index]++;
index--;
}

}

int main(int argc, char *argv[])
{
int i;
int array[10];
for(i=0; i<10 ;i++){
array[i] = i;
}
bump(&array[0], sizeof(array)-1);
for(i=0; i<10 ;i++){
printf("array[%d]=%d\n", i, array[i]);
}

return 0;
}




January 26, 2010

Erlang::Making Random List

just for memo.

make_randomlist_u(X,Y,Z) ->
case X of
Y -> Z;
_ -> X1 = X + 1, make_randomlist_u(X1,Y,[random:uniform(1000)|Z])
end.

make_randomlist(X) ->
make_randomlist_u(0,X,[]).

Output:
3> test:make_randomlist(10).
[478,667,916,598,312,502,946,724,444,93]
4> lists:sort(test:make_randomlist(10)).
[6,143,160,210,215,422,458,559,597,698]


January 25, 2010

Erlang Programming::Exercise 2-3

How about this?

-module(boolean).
-export([b_not/1, b_and/2, b_or/2, b_nand/2]).

b_nand(true,true) ->
false;
b_nand(_,_) ->
true.

b_not(A) ->
b_nand(A,A).

b_and(A,B) ->
b_not(b_nand(A,B)).

b_or(A,B) ->
b_nand(b_not(A),b_not(B)).



I guess there is a type in the textbook on p.44, the name of a module should be same to the file name....
Output is ...
8> c(boolean).                                                  
{ok,boolean}
9> boolean:b_not(false).
true
10> boolean:b_and(false,true).
false
11> boolean:b_and(boolean:b_not(boolean:b_and(true,false)),true).
true


book:: Programming Erlang

I got interested in Erlang these days, and read this book - yes, that's right. This is not just another language, but some sort of "killer" language for the software of this age, namely concurrency and distributed computing.
I was amazed how easy it is to write a RPC in Erlang, writing distributed software would become substantially easier when using Erlang instead of C++ or Java. If you are interested in the topics of these area, this book is a must.