Yaws Installation: Install erlang Add path to erlang/bin directory to System Path Install Yaws Run Yaws server by double-clicking Yaws-xxx/bin/yaws.exe Files under Yaws-xxx/www directory can be viewed in web browser with URL http://localhost:8080/ Erlang is a functional programming language. This is very different from C++, C#, and Java, which are procedural programming languages. Procedural languages stress organization of data, and sequences of instructions which operate on some global state. Functional languages, on the other hand, treat programs as evaluations of functions without a global state. While threads are considered a complicated and error-prone topic in most languages, Erlang provides language-level features for creating and managing processes with the aim of simplifying concurrent programming. Processes communicate using message passing instead of shared variables, which removes the need for locks. Erlang, together with libraries and the real-time distributed database Mnesia, forms the Open Telecom Platform (OTP) collection of libraries. Age = 3. % Variables must start with a capital letter. % All other Erlang words begin with a lower-case letter. % Once assigned a value, a variable is said to be bound. % Once assigned, the variable type or value cannot be changed. % Erlang interpret statements as equations, and if Age = 3, Age cannot equal 2. Erlang Shell halt(). % shutdown erlang (^C and init:stop(). also work) help(). % display shell internal commands cd("C:\\Documents and Settings\\Sigal\\My Documents\\Programming\\Erlang"). file:get_cwd(). % print current working directory f(). % forget all variable bindings b(). % prints the current variable bindings h(). % print the history list (default size of 20) e(N). % repeat command number N v(N). % the return value of command number N Erlang Debugger debugger:start(). % open the debugger monitor window. im(). % as above? erlc +debug_info Module.erl % compile a module with the debug_info flag, so it is traceable c(Module, [debug_info]). % ...alternatively, from the erl prompt compile:file(Module, [debug_info]). % ...another alternative pman:start(). % starts the process manager; double-click on a process to open it's trace window Arithmetic 2 + 3. % every statement ends with a period. % Integer arithmetic is exact, so you don't have to worry about arithmetic % overflows or not being able to represent an integer in a certain word size. 5 / 3. % 1.6666666666666667 5 div 3. % 1 (quotient) 5 rem 3. % 2 (reminder) is_integer(4). % true abs(-7). % 7 round(7.5). % 8 trunc(7.5). % 7 float(1). % 1.00000 math:sqrt(9). % 3 math:pow(2,3). % 8 list_to_integer("5"). % convert string to number Atoms An atom is a global, non-numerical constant, similar to enumerated types. For example: monday, green, inches An atom should be enclosed in single quotes (') if it does not begin with a lower-case letter or if it contains other characters than alphanumeric characters, underscore (_), or @. atom_to_list(hello). # converts an atom to a string list_to_atom("hello"). # atoms are not garbage collected and remain in the atom table. Tuples Point = {point, 10, 45}.% A tuple is a finite sequence of values. {point, X, Y} = Point. % '=' is the pattern matching operator. Now X=10, Y=45. _ in front of a variable indicates that the value is never used in the scope: {_atom, X, _Y} = Point. {_, X, _} = Point. % '_' is an anonymous variable and is never bound. element(3, Tuple). % returns the 3rd element in tuple setelement(3, {1,2,3,4}, three). % {1,2,three,4} replace element erlang:append_element({1,2,3}, 4). % {1,2,3,4} append element is_tuple({1,2}). % true size({1,2}). % 2 tuple_size({1,2}). % 2 tuple_to_list({1,2,3}). % [1,2,3] list_to_tuple([1,2,3]). % {1,2,3} Lists List = [1, 2, 3]. [First, Second | Tail] = [1, 2, 3, 4]. % First=1, Second=2, Tail=[3,4] [Head | Tail] = [1]. % Head=1, Tail=[] NewList = [First | List]. % add a head to a list length(List). % returns List length [1,2,3] ++ [4,5,6]. % [1,2,3,4,5,6] [1,2,2,3,4,4] -- [2,4]. % [1,2,3,4] hd([1,2,3]). % 1 (returns the head of the list) tl([1,2,3]). % [2,3] (returns the tail of the list) lists:seq(1,5). % returns [1,2,3,4,5] lists:nth(3, List). % returns the 3rd element in list lists:last([1,2,3]). % 3 lists:sum([2, 3, 4]). % returns the sum of numbers in the provided list lists:max([2, 3, 4]). lists:reverse([2, 3, 4]). lists:sort([2, 1, 3]). % [1,2,3] lists:split(2, [3,4,10,9,7]). % {[3,4],[10,9,7]} lists:zip([1,2,3],[5,6,7]). % [{1,5},{2,6},{3,7}] lists:delete(2, [1,2,3,2]). % [1,3,2] lists:member(X, L) returns true if X is a member of list L lists:flatten([[1,2], 3, [4,5]]). % [1,2,3,4,5] % Searching for a tuple in a list of tuples: {value, Tuple} = lists:keysearch(Key, Pos, List) List = [{4,one,1}, {5,two,2}, {6,three,3}]. # Pos is the position of the Key field in the tuples. lists:keysearch(two, 2, List). % {value,{5,two,2}} keysort(N, TupleList1) -> TupleList2 % Returns a list containing the sorted elements of the list TupleList1. % Sorting is performed on the Nth element of the tuples. lists:filter(P, L) returns a new list of all elements E in L such that P(E) is true. Fun = fun(X) -> X * 2 end. lists:map(Fun, [1, 2, 3]). % map/2 applies function Fun to every element in the provided % list and returns a list of the computed values. Fun = fun(X) -> [X,X] end. % a function that returns a list lists:flatmap(Fun, [1, 2, 3]). % returns the flatten list [1,1,2,2,3,3] Fun = fun(X) -> io:format("hello ~p~n", [X]) end. lists:foreach(Fun, [1, 2, 3]). % foreach/2 applies function Fun to every element in the provided % list; no value is returned lists:foldl(fun(Element, Accumulator) -> ... , InitAcc, List). The function argument must take two arguments, and must return the new value of the accumulator. The second argument to foldl is the initial value of the accumulator; The third argument is the list of which to perform the fold. foldl traverses the list from beginning to end, foldr traverses the list in the opposite direction. foldl is preferred because it is tail-recursive. count(String) -> %% Example: count the number of a's in a string lists:foldl(fun(Element, Acc) -> case Element of $a -> Acc + 1; _ -> Acc end end, 0, String). List Comprehension [F(X) || X <- L] % equivalent to map(F, L) [X || {a, X} <- [{a,1}, {b,2}, {a,4}, hello]]. % [1,4] (<- operates like a filter) [X+2 || X <- [1,2,3,4], X rem 2 == 0] % [4,6] [{A,B} || A <- [1,2,3], B <- [1,2,3], A + B < 4]. % [{1,1},{1,2},{2,1}] The most general form of a list comprehension is [X || Qualifier1, Qualifier2, ...] Each qualifier is either a generator or a filter (guard). Generators are written as Pattern <- ListExpr where ListExpr must be an expression that evaluates to a list of terms. Filters are either predicates (functions that return true or false regarding a property of members of a set) or boolean expressions. Strings String = "abc". % in Erlang strings are just a list of integers When the shell prints the value of a list it prints the list as a string, but only if all the integers in the list represent printable characters: [83,117,114,112,114,105,115,101]. % print "Surprise" $a is equivalent to C and Java 'a'; $\n is a newline character and $$ is '$' string.to_lower("HELLO WORLD") string.to_upper("hello world") string:concat("str1", "str2"). % "str1str2" Modules % File test.erl -module(test). % Module declaration. module name must match file name -export([fac/1]). % allow function 'fac' which takes 1 argument % to be called from outside the module (public function) fac(1) -> 1; % Initial condition: the factorial of 1 is 1; % the ";" indicates that there is another alternative of this function ahead fac(N) -> N * fac(N-1). % calculates the factorial of a number c(test). % compile module named "test"; if ok, returns {ok, test} % a compiled module has the extension .beam l(test). % load module if it's already compiled test:func(3). % call function 'func' in module 'test' with '3' as an argument Functions in Erlang are uniquely identified by their name, their arity and the module in which they are defined. Two functions in the same module might have the same name but a different arity. If so they are considered two unrelated functions. -compile(export_all). % a directive to export all functions defined in the module at compile time. % Another way of doing this is to specify an option on compiling the file: c(my_module, [export_all]). my_module:module_info(). % list all attribute of the module % hello.erl -module(hello). -export([hello/0]). % export a function with 0 arguments hello() -> io:fwrite("Hello World~n", []). % call the fwrite function in the io module % the ~ is equivalent to the % character in C's printf % ~n is the format specifier to output a newline Erlang has no global state. This means no global variables. Modules cannot have variables. The scope of an Erlang variable is limited to the function (or case, or if statement) it is declared in. funs are anonymous functions Fac = fun(1) -> 1; (N) -> N * fac(N-1) end. A function can return a function instead of a value: Mult = fun(Times) -> ( fun(X) -> X * Times end ) end. Triple = Mult(3). % Mult(3) returns 'fun(X) -> X * 3 end'. Triple(5). % returns 15. %misc.erl -module(misc). -export(total/1]). -import(lists, [sum/1, middle/1]). total(L) -> sum(L). % since sum/1 was imported, we don't need to type lists:sum(L) % Function argument's pattern matching: middle({ _, Second, _ }) -> Second; % returns the second element of a 3-element tuple middle([ _, Second | _ ]) -> Second. % ...or the second element of a list Comparisons A == B % equality test; 1 == 1.0 returns true A =:= B % equality test; also compares data type A /= B % inequality test A =/= B % inequality test; also compares data type A =< B % less than or equal to A >= B % greater than or equal to true % The boolean atoms true and false are guard expressions and andalso % returns false if the first argument is false, without evaluating the 2nd or orelse % returns true if the first argument is true, without evaluating the 2nd xor % returns true if one of its arguments is true and the other false not % unnary negation operator; returns true if its argument is false, and vice versa ((3>2) or (3>1)). % composite boolean expression have to be enclosed in parenthesis Guards Guards are additional constraints that can be place in a function clause. Guards are placed before the -> separating the clause head from the body. The clause will be selected only if the pattern matches and the guard expression evaluate to the atom 'true'. Func(pattern) when guard, guard, ... -> function body Guards do not allow reference to any user-defined function. is_integer(X), X>3, ... % , means 'and' is_integer(X); X>3, ... % ; means 'or' Conditional Statements is_even(X) -> if X rem 2 == 0 -> true; true -> false end. is_even(X) when X rem 2 == 0 -> true; % as above using a guard is_even(_) -> false. many(X) -> case X of [] -> none; [_One] -> one; [_One, _Two] -> two; [_One, _Two, _Three | _ ] -> many; N when N > 0 -> guard_example end. Erland has no for loop, but we can make one: for(Max, Max, F) -> [F(Max)]; for(I, Max, F) -> [F(I)|for(I+1, Max, F)]. apply(Mod, Fun, [Arg1, Arg2, ...]). % determine the function to be called dynamically % (Mod - module, Fun - function, ArgN - the arguments to Fun, put in a list) % If the number of arguments is known at compile time, we can use: Mod:Fun(Arg1, Arg2). date(). % returns the current date as a tuple of {Year, Month, Day} time(). % returns the current time as a tuple of {Hour, Minute, Second} io:get_line("type you name: "). % read line from standard input io:get_chars("type 2 chars: ", 2). % read 2 chars from standard input io:read("Erlang input: "). % reads an Erlang term from standard input io:write(Term). % writes to standard output erlang:display(Term). % writes to standard output; good for debugging io:format("Term is ~w", [Term]).% writes a formatted output ~c % An ASCII code to be printed as a character ~f % A float to be printed with six decimal places ~e % A float to be printed in scientific notation, showing six digit in all ~w % Writes any term in standard syntax ~p % As ~w, but prettier, introducing line breaks, indentation, and outputting lists as strings where possible ~W, ~P % As ~w or ~p, but eliding structure at a depth of 3. These take an extra argument % in the data list indicating the maximum depth for printing terms. For example: % io:format("~W~n",[[1,2,3,4], 3]). % [1,2|...] ~B % Shows an integer to base 10 The full control sequence has the form ~F.P.PadC, where F is the field width, P is the precision, Pad is the padding character and C is the control Character Recursion Examples Increment every element in a list by 1: inc([]) -> []; inc([Head | Tail]) -> [Head + 1 | inc(Tail)]. Find avarage of all list elements: average(List) -> sum(List) / len(List). sum([]) -> 0; sum([Head | Tail]) -> Head + sum(Tail). len([]) -> 0; len([_ | Tail]) -> 1 + len(Tail). Returning a list of all the even elements of a list: even([]) -> []; even([Head | Tail]) when Head rem 2 == 0 -> [Head | even(Tail)]; even([_ | Tail]) -> even(Tail). Finding if an element is a member of a given list: member(_, []) -> false; % no element is a member of an empty list member(H, [H | _]) -> true; member(H, [_ | T]) -> member(H, T). Tail recursion is where the last operation of the function, the tail call, is a recursive call. A tail recursion obliterate the need to save data on a stack. Head recursive functions may be converted to tail recursive ones by using an additional accumulator argument. Finding the sum of the elements in a list by tail recursion: sum(List) -> sum_acc(List, 0). sum_acc([], Sum) -> Sum; sum_acc([Head | Tail], Sum) -> sum_acc(Tail, Head + Sum). Increment every element in a list by 1 by tail recursion: inc(List) -> inc_acc(List, []). inc_acc([], Acc) -> reverse(Acc); % The final list is in reverse order, so need to be reversed inc_acc([Head | Tail], Acc) -> inc_acc(Tail, [Head+1 | Acc]). % Acc is an accumulator list Finding the avarage of all list elements with tail recursion: average(List) -> average_acc(List, 0, 0). average_acc([], Sum, Length) -> Sum/Length; average_acc([H | T], Sum, Length) -> average_acc(T, Sum + H, Length + 1). Handling Errors X=2. try (X=5) of % (x=5) returns 5 when successful Val -> {normal, Val} catch error:Error -> {error, Error} % match patterns in the error class end. % {error, {badmatch,5}} is the returned value try (throw(non_normal_return)) of Val -> {normal, Val} catch throw:Error -> {throw, Error} end. % {throw, non_normal_returm} is the returned value % throwing an error to be catched by a non-local try-catch code is discouraged 1/0. # Generates a runtime error. catch 1/0. # Instead of generating a runtime error, catch 'expression' returns # a tuple of the format {'EXIT', {Reason, Stack}}. # catch doesn't differentiate between the error classes error, throw and exit. X = (catch 1/0).# Parentheses are needed to give catch higher precedence than the assignment # Don't use catch - this is legacy code - use try-catch Records A record is a data structure with a fixed number of fields that are accessed by name (unlike tuples were fields are accessed by position) -record(person, {name,age,phone}). % record definition -record(person, {name,age=0,phone=""}). % record definition with default values % In the absence of a default value, the default is the atom 'undefined'. Person = #person{name="Joe", age=21, phone="999-999"} % record instance Person = {person, "Joe", 21, "999-999"} % same, in tuple syntax - but don't use! Records are implemented by the compiler as tuples. To see the implementation, compile your file using the 'E' option compile:file(myMod, ['E']) and see file myMod.E (no .beam produced) Person#person.name % accessing a record's field value #recordType.field cannot contain variables. This is because it is handled by the compiler and converted to its respective value before the code is run and the variables are bound. NewPerson = Person#person{age=37} % all other field value of Person are copied to new instance joe() -> #person{name="Joe", age=21, phone="999-999"}. % function to create record instance birthday(#person{age=Age} = P) -> P#person{age=Age+1}. % function to update record instance showPerson(#person{age=Age, phone=Phone, name=Name}) -> % read record instance fields into variables io:format("name: ~p age: ~p phone: ~p~n", [Name,Age,Phone]). Record fields can contain any valid Erland data type. -record(name, {first, surname}). % the name field in a person record could itself be a record P = #person{name = #name{first = "Slobo", surname="Miskovic"}} First = (P#person.name)#name.first Sort list of records: Sorted = lists:sort(fun(Elem1, Elem2) -> Elem1#tbl_name.field < Elem2#tbl_name.field end, List) % fun has to return true when Elem1, Elem2 are in the required order Data Base rr("moduleName"). % load all record definitions in the module to the shell rd(recordName, {field1, field2, ...}). % define a record in the shell rl(). % list all record definitions currently visible in shell rf(). % forget all record definitions record_info(size, my_record). % return the number of fields in my_record record_info(fields, my_record). % return the field names in my_record is_record(record_instance, my_record). Record = #usr{}. % create a tuple with elements of the default type as a usr table record Record = #usr{id = "A12345"}. % as above, with value set for the id element Record#usr.id. % get the id element of Record element(2, Record). % as above #usr.id returns the position of the id field in the record (to use with keyseach) #usr{id=A2} = Record. % assigns the id value to variable A2 #usr{id=A2, invoice = InvID} = Record. % two assignments in one call mnesia:write(Record). % writes a record to corresponding table. returns ok mnesia:delete_object(Record). % delete record from DB mnesia:delete({Tbl_name, Id}). % delete record from DB table by its Id mnesia:clear_table(Tbl_name). % delete all entries from table mnesia:read({Tbl_name, Id}). % retrieve a record by its Id mnesia:dirty_match_object(#usr{score = 1, _='_'}). % find records in table where score==1; _ is * The following function extracts the names of the female employees: mnesia:select(employee, [{#employee{sex = female, name = '$1', _ = '_'}, [], ['$1']}]). Find the names of all male persons with an age over 30 in table my_table: Head = #person{name='$1', sex=male, age='$2', _='_'}, Guard = {'>', '$2', 30}, Result = '$1', mnesia:select(my_table, [{Head, [Guard], [Result]}]) {atomic, Results} = mnesia:transaction(Fun). Fun contains operations such as read, write, and delete. If successful, the call returns a tuple {atomic, Result}, where Result is the return value of the last expression executed in Fun. If the transaction fails, {aborted, Reason} is returned. Always pattern-match on {atomic, Result}, as your transactions should never fail unless mnesia:abort(Reason) is called from within the transaction. A transaction guarantees that the database will be taken from one consistent state to another, that changes are persistent and atomic across all nodes, and that transactions running in parallel will not interfere with each other. An atomic operation refers to a set of operations that can be combined so that they appear to the rest of the system to be a single operation with only two possible outcomes: success or failure. When executing your Fun in a transaction, Mnesia will put locks on the objects it has to manipulate. If another process is holding a conflicting lock on an object, the transaction will first release all of its current locks and then restart. Side effects such as an io:format/2 call, or sending a messager, might result in the printout or the message being sent hundreds of times. Therefore have your Fun free of side effects. dirty operations execute outside the scope af a transaction without setting any locks. They are about 10 times faster than their counterparts that are executed in transactions. add_table_index(Tbl_name, Field) % index the table on secondary fields (or keys) at run time del_table_index(Tbl_name, Field) mnesia:index_read(Tbl_name, Value, Field) % retrieve record by the Value of a secondary index field qlc (Query List Comprehension) qlc:q(Expression || Qualifier1, Qualifier2, ...) -> QueryHandle qlc:e(QueryHandleOrList [,Options]) qlc:do(QueryHandleOrList) % runs qlc:e(Q) inside a mnesia transaction Qualifiers are either filters or generators. Filters are Erlang expressions returning bool(). Generators have the form Pattern <- ListExpression, where ListExpression is an expression evaluating to a query handle or a list. Query handles are returned from qlc:table/2, qlc:append/1,2, qlc:sort/1,2, qlc:keysort/2,3, qlc:q/1,2, and qlc:string_to_handle/1,2,3. qlc:q([ X#user.address || X <- mnesia:table(user), X#user.name == "Slobo" ], {unique, true}) Macros Macros allow you to write abbreviations of Erlang constructs that the Erlang preprocessor (EPP) expands at compile time. -define(TIMEOUT, 1000). receive after ?TIMEOUT -> ok end % receive after 1000 -> ok end -define(FUNC,X). -define(TION,+X). double(X) -> ?FUNC?TION % double(X) -> X + X. -define(Multiple(X,Y), X rem Y == 0). % Parameterized Macros func(Z,W) when ?Multiple(Z,W) -> true. % func(Z,W) when Z rem W == 0 -> true. %-define(DBG(Str, Args), ok). % production version, commented out -define(DBG(Str, Args, io:format(Str, Args)). % for debugging birthday(#person{age=Age} = P) -> ?DBG("In records1:birthday(~p)~n", [P]), P#person{age=Age+1}. -define(VALUE(X), io:format("~p = ~p~n", [??X, X])). % ??X will be expanded as a text string test()-> ?VALUE(2 + 3). % "2 + 3" = 5 Predefined macros: ?MODULE % the name of the module in which it is used ?MODULE_STRING % as above, in string format ?FILE % the name of the file in which it is used ?LINE % the line number of the position at which it is used Conditional macros will be expanded in different ways according to flags passed to the compiler: -ifdef(debug). % if the debug flag is set -define(DBG(Str, Args), io:format(Str, Args)). -else. -define(DBG(Str, Args), ok). -endif. c(Module, [{d,debug}]). % To turn on system debugging, set the debug flag c(Module, [{u,debug}]). % Unset the flag -undef(Flag). % unset the Flag -ifndef(Flag). % if Flag is not set execute the statements that follow It is customary to put record and macro definitions into an include file with the suffix .hrl. -include("File.hrl"). % The -include directive is usually placed after the module and export directives c(Module[{i, Dir}]). % Add path Dir to list of paths where include files are searched Web Programming out(Arg) -> % Getting data from a web form [{"name1", Value1},{_,Value2}, {_,Value3}] = yaws_api:parse_query(A), {html, HTML}. Processes Messages sent from one single process to another are guaranteed to be received in the same order in which they were sent. If a message is sent to a nonexistent process, it is thrown away without generating an error. Message passing is asynchronous: a sending process will not be suspended after sending a message; it will instead immediately continue executing the next expression in its code. A message can consist of any valid Erlang term. Making the shell crush will automatically result in a new shell process. processes(). % list all running processes numbers i(). % list process identifier, the function that spawned it, the function in which the process is currently executing and other info. The column Reds is the reduction number: when a process is dispatched, it is assigned a number of reductiontions it is allowed to execute, a number which is reduced for every operation executed. As soon as the process enters a receive clause where none of the messages matches or its reduction count reasches zero, it is preempted. erlang:bump_reductions(Num) % increment a process reduction counter erlang:yield() % preempt the process Pid = spawn(Module, Function, Args). % spawn new process Module:Function(Args) Pid = self(). % returns the pid of the process in which it is evaluated Pid ! hello. % passing a message to process Pid flush(). % retrieve all received messages and remove them from mailbox Pid2 = pid(0,30,0). % generate a new process identifier Pid1!Pid2!Pid3!Message % sending a message to multiple processes receive Pattern1 when Guard1 -> exp1, exp2; % message handling Pattern2 when Guard2 -> exp3, exp4 % oldest messages are received first end, % a process is suspended at the receive clause until a matching message is received Example: calculate area % Run it with -module(area). % Pid = area:start(). -export([start/0, area/2, loop/0]). % area:area(Pid, {rectangle, 3, 4}). start() -> spawn(area, loop, []). area(Pid, What) -> rpc(Pid, What). % abstraction - end user don't work directly with remote processes % Pid is the process ID of the user requesting process rpc(Pid, Request) -> % rpc: remote procedure call Pid ! {self(), Request}, receive { Pid, Response } -> Response end. loop() -> receive { From, { rectangle, H, W }} -> From ! { self(), W * H}, loop(); { From, { circle, R }} -> From ! { self(), (math:pow(R,2)) * 3.14}, loop(); { From, Other} -> From ! { self(), Other } end. Erlang processes are lightweight processes whose creation, context switching, and message passing are managed by the VM. There is no relatin between OS threads and Erlang processes, making concurrency-related operations not only independent of the underlying operating system, but also very efficient and highly scalable. Benchmarks comparing Erlang concurrency models to their counterpart in C# or Java are magnitudes better. With Erlang, we are dealing with one OS thread per processor (or core). In Java and C# each process is represented by an OS thread. register(Alias, Pid). % allow refering to a process by an Alias. % give your process the same name as the module in which it is defined unregister(Pid). registered(). % return list of registered names regs(). % return table of registered names, Pids, module:function name whereis(Alias). % return the pid associated with the Alias Sending a message to a nonexistent process identifier does not produce an error. Sending a message to a nonexistent registered process causes the calling process to ternimate with a badarg. That's because registered processes are assumed to provide a service and their absence is treated as a bug. If you don't want the calling process to terminate, wrap a try ... catch around the call. receive Pattern1 when Guard1 -> exp1, exp2; Pattern2 when Guard2 -> exp3, exp4 after Timeout -> exp5, exp6 % executed if after Timeout milliseconds no message arrived. % Timeout can be set to the atom infinity end If the message is sent after Timeout, it will remain in the inbox and will be read first if the function including the receive statement is called again. That might be an old answer to a new question. To avoid it empty the mailbox before the receive statement: read(Key) -> flush(), db ! (self(), {read, Key}), receive {read, Response} -> {ok, Response}; {error, Reason} -> {error, Reason} after 1000 -> {error, timeout} end flush() -> receive {read, _} -> flush(); {error, _} -> flush() after 0 -> ok end. Suspend a process for a period T in milliseconds: sleep(T) -> receive after T -> true % can also specify an expression instead end Benchmarking timer:tc(Module, Function, [Args]) % execute Module:Function(Args) and return the time it took in microseconds % Convert erlang objects to Jsavscript objects by using the atoms struct or array. % To see how the objects are going to look like in Javascript type JavaScript use json:encode io:format("~s~n", [json:encode({struct, [ {a, 1}, {b, "string"} ]})]). % {"a":1,"b":"string"} io:format("~s~n", [json:encode({struct, [ {a, {struct, [{c, 2}]}}, {b, "string"} ]})]). % {"a":{"c":2},"b":"string"} io:format("~s~n", [json:encode( {array, [1,2,3]} )]). % [1,2,3] io:format("~s~n", [json:encode( {array, [{struct, [{val, 2.5}, {date, 20091011}, {ref, {struct, [{min, 1.0}, {max, 2.4}]}}]}]} )]). % [{"val":2.5,"date":20091011,"ref":{"min":1.0,"max":2.4}}]