A FEW ERLANG EXAMPLES


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(counter).
-export([start/0,loop/1,increment/1,value/1,stop/1]).

%% First the interface functions.
    start() ->
        spawn(counter, loop, [0]).
   
    increment(Counter) ->
        Counter ! increment.

    value(Counter) ->
        Counter ! {self(),value},
        receive
              {Counter,Value} ->
                                Value
        end.

    stop(Counter) ->
        Counter ! stop.

%% The counter loop.

    loop(Val) ->
               receive
                   increment ->
                               loop(Val + 1);
                   {From,value} ->
                               From ! {self(),Val},
                               loop(Val);
                    stop -> % No recursive call here
                            true;
                    Other -> % All other messages
                            loop(Val)
                end.



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%A Simple Client-Server system:


-module(message).
-export([loop/0,client/2]).
          
  loop() ->
            receive
                   {From,{add, A, B}} ->
                                        From!A+B,
                                        loop();

                   {From,{mul, A, B}} ->
                                        From!A*B,
                                        loop();

                   {From,{minus, A, B}} ->
                                        From!A-B,
                                        loop();

                   {From,{division, A, B}} ->
                                        From!A/B,
                                        loop();

                    _Other ->
                                         loop()
             end.


  client(Pid,Request)->
                    Pid ! {self(), Request},
                    receive
                        Response ->io:format("Response is ~p~n" ,[Response])
                    end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

An Erlang program simulating a finite state machine
recognizing the regular language represented by the regular expression
abc*+c(bb)*.
Each state has to be represented by a process.
(by F.Barbanera)

-module(regExpr).
-export([manager/0,state/2,create/0]).

% Module for automaton for a regular languages on {a,b,c}.
%
% Each state is a process. Many strings can be parsed in parallel. 
%
% create : creates a particular automaton (the one corresponding to (ab)* in this simple example)
%                   together with its manager. 
%
%          A parsing request can be sent to the manager by means of a triple {requestParsing,ID,List}
%          where ID is the PID of whom makes the request, and List is the string to be parsed.
%
%          For sake of simplicity a string is represented by a list of atoms that represents characters.
%
%          The manager sends the request to the initial state and receives the answer that is then
%          delivered to whom made the request. 
%          The original string to be parsed is kept through all the parsing process and sent back with the 
%          answer in order one can send onother request even before one gets the answer of the previous request. 
%
% manager : It is the function corresponding to the manager of the automaton.
%          Once spawned by the create function, the manager waits for the address of the initial state, 
%          that the create function itself sends to it (This procedures is a simple trick necessary since
%          the manager and the initial state need the PID of each other.)
%
% state   : It is the function corresponding to a state. Its arguments are the PID of the manager
%           and one atom (final or nofinal) representing whether the spawned state is final or not.
%           Once spawned by the create function, a state waits for a triple of PIDs
%           corresponding, respectively, to the states it has to be connected to for the characters a, b, or c.
%           In case a state is not connected to another state for a particular character (and hence the
%           string has to be rejected), the corresponding element in the triple is the atom none instead of a PID.
%           (As for the manager, this trick is needed in order to have automata with cliques.          

%% abc*+c(bb)*
%
%       a    b   c       Final States = q2, q3
% init  q1       q3
%   q1      q2 
%   q2           q2     
%   q3      q4
%   q4      q3
%


create () ->          %%we create the manager and the (process-)states. The PID of manager is returned.

                      IDmanager = spawn(exprReg,manager,[]),
                      IDinit    = spawn(exprReg,state,[IDmanager,notfinal]),
                      IDq1      = spawn(exprReg,state,[IDmanager,notfinal]),
                      IDq2      = spawn(exprReg,state,[IDmanager,final]),
                      IDq3      = spawn(exprReg,state,[IDmanager,final]),
                      IDq4      = spawn(exprReg,state,[IDmanager,notfinal]),

                      %%we connect the manager to qinit and the various states among themselves

                      IDmanager!IDinit,
                      IDinit!{IDq1,none,IDq3},
                      IDq1!{none,IDq2,none},
                      IDq2!{none,none,IDq2},
                      IDq3!{none,IDq4,none},
                      IDq4!{none,IDq3,none},
                      IDmanager.
                      


manager() -> receive
               IDinitial -> loopmanager(IDinitial)
             end.                       
                   

loopmanager(IDinitial) ->
             
               receive

                   {requestParsing,ID,List} -> IDinitial ! {List,ID,List};
                                               
                   {accepted,ID,List}       -> ID ! {accepted,List};

                   {rejected,ID,List}       -> ID ! {rejected,List}

               end,
             
               loopmanager(IDinitial).




                    


state(IDmanager,Final) -> receive
                             {IDA,IDB,IDC} -> loop(IDA,IDB,IDC,IDmanager,Final) 
                          end. 




 loop(IDA,IDB,IDC,IDmanager,Final) ->
           
         
         receive

              {[],ID,List}          ->    if 
                                             (Final == final)  -> IDmanager ! {accepted,ID,List};
                            
                                              true             -> IDmanager ! {rejected,ID,List}
                     
                                          end;

              {[ Char | Cs ],ID,List}  ->  Next = (if (Char == a) -> IDA; (Char == b) -> IDB; (Char == c) -> IDC end),
                                           
                                           if
                                              (Next == none)    ->  IDmanager ! {rejected,ID,List};

                                               true             -> Next ! {Cs,ID,List}
                                           end
          end,
             
         loop(IDA,IDB,IDC,IDmanager,Final).


% The above program can be modified in order the function create takes the description of
% a finite automaton (its transition table) and returns the PID of the manager of the 
% corresponding system. Such a program is described in the solution of Exercise 14 in
% http://www.dmi.unict.it/~barba/PROG-LANG/ESERCIZI/EserciziActorsErlang/esercizi.html


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%Token Ring

% The following example has been taken from
% http://trigonakis.com/blog/2011/05/26/introduction-to-erlang-message-passing/


%This application creates NumNodes processes and arranges them in a ring 
%(every process has one next process). 
%Then the coordinator inserts a token in the first node of the ring. 
%Every node (process) receiving the token increases its value by 1 and 
%sends it to the next node. The application stops when the token has value 
%greater than the MAXVAL.




-module(ring).
-export([create/1, node/2, connect/1]).
 
-define(MAXVAL, 100000).
 



%creates the ring's nodes, connects them in a ring, sends the token in the ring, and
%collects the exit messages from the nodes



create(NumNodes) 
                 when is_integer(NumNodes), NumNodes > 1 ->

    Nodes = [spawn(?MODULE, node, [ID, self()]) || ID <- lists:seq(1, NumNodes)],
            % notice that the above expression denotes a list using
            % the mechanism of list comprehension, similar to Haskell list comprehension
            % Remember that the function spawn returns a process identifier,
            % so to the Nodes variable we associate the list of the created process nodes.
    ring:connect(Nodes),

    hd(Nodes) ! {token, 0},

    getexits(Nodes).
 




%collects the exit messages from the nodes


getexits([]) ->
    io:format("[Coord] Done.~n"),
    ok;

getexits(Nodes) ->
    receive
	{Node, exit} ->
	    case lists:member(Node, Nodes) of
		true ->
		    getexits(lists:delete(Node, Nodes));
		_ ->
		    getexits(Nodes)
	    end
    end.
 





%little trick in order to connect the last with the first node
%handle the [nd0, nd1, ..., ndN] list as [nd0, nd1, ..., ndN, nd0]

% Notice the use of a particular sort of pattern matching, enabling
% to associate the whole input to the variable N and the head of the
% input list to the variable H.
% This particular sort of pattern matching is present also in Haskell (as-pattern)
% and PICT (layered pattern). 
% In Haskell and PICT the following notation is used:  x@p (where x is a variable and p a pattern).




connect(N = [H | _]) ->

    connect_(N ++ [H]).
 





%connects the nodes to form a ring


connect_([]) ->
    connected;

connect_([_]) ->
    connected;

connect_([N1, N2 | Nodes]) ->

    N1 ! {self(), connect, N2},

    connect_([N2 | Nodes]).
 




% The computation in each process node consists in the evaluation of
% the node function below.
% The node function initially waits for the next node's pid and then proceed
% by evaluating the other node function (that can be recognized as different from
% the first one, since it has three arguments instead of two.


node(ID, CrdId) ->
    receive
	{CrdId, connect, NxtNdId} ->
	    io:format("[~p:~p] got my next ~p~n", [ID, self(), NxtNdId]),
	    node(ID, CrdId, NxtNdId)
    end.
 



%the main functionality of a node; receive the token, increase its value and send
%it to the next node on the ring



node(ID, CrdId, NxtNdId) ->

    receive
	{token, Val} ->
	    if
		Val < MAXVAL ->
		    NxtNdId ! {token, Val + 1},
		    node(ID, CrdId, NxtNdId);
		true ->
		    io:format("[~p:~p] token value ~p~n", [ID, self(), Val]),
		    case erlang:is_process_alive(NxtNdId) of
			true ->
			    NxtNdId ! {token, Val + 1};
			_ ->
			    ok
		    end,
		    CrdId ! {self(), exit},
		    done
	    end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The (sequential) quicksort in Erlang. This example (but the Haskell version of 
% the partition function) is partially taken from slides 
% by David Chisnall for the talk 
% Introduction to Erlang A Language For Message-Passing Concurrency
 


-module (qs).
-export ([qs /1]).

 
qs([]) -> []
;
qs([X]) -> [X]
;
qs( List ) ->
    [ Pivot | Sublist ] = List ,
    {Less , Greater } = partition ( Sublist , Pivot ,[],[]),
    qs( Less ) ++ [ Pivot ] ++ qs( Greater ).

% Notice how in Erlang we can have sequences of expressions, as in OCaml.
% As in OCaml, the value of a sequence of expressions is the value of the 
% last one, the previous are usually used for the effects their evaluation have
% (tipically the introduction of a local valriable, like the use of 'where' or 'let'
% in Haskell)

partition ([],_,Less , Greater ) -> {Less , Greater }
;
partition ([X| List ],Pivot , Less , Greater ) ->
                      if
                            X > Pivot ->
                                    partition (List , Pivot , Less , [X| Greater ])
                            ;
                            true ->
                                    partition (List , Pivot , [X| Less ], Greater )
                       end .

% Notice how this fuction is a tail-recursive version of the partition fuction.
% Erlang can recognize tail-recursive functions and compile them very efficiencely.
% Fuctions corresponding to the computation of a process should be necessarily
% tail-recursive whenever the process can go on indefinitely.

% Let us see a non tail-recursive version of the partition function in Haskell:
% This version returns a pair of list, whereas the Erlang one returns a tuple of
% two lists.


partition [] piv = ([],[])


partition (x:xs) piv | x<piv     = ((x:lessxs),greaterxs)
                     | otherwise = (lessxs,(x:greaterxs))
                    where
                          (lessxs,greaterxs) = (partition xs piv)

% The following is a concurrent version of the quicksort in Erlang,
% where each call of the function create two different processes for sorting
% the two sublists returned by the partition function.


pqs([],Parent ,Tag) -> Parent ! {Tag ,[]}
;
pqs([X],Parent ,Tag) -> Parent ! {Tag ,[X]}
;
pqs(List , Parent , Tag) ->
               [ Pivot | Sublist ] = List ,
               {Less , Greater } = partition ( Sublist , Pivot ,[], []),
               spawn (pqs ,pqs ,[Less , self () , less ]),
               spawn (pqs ,pqs ,[ Greater , self () , greater ]),
               receive {less , LessSorted } -> true end ,
               receive { greater , GreaterSorted } -> true end ,
               Parent ! {Tag , LessSorted ++ [ Pivot ] ++ GreaterSorted }.


% Notice how we need to use two 'receive' expressions, since we need to be sure
% to receive both the to ordered sublists before going on.



