General syntax

reverse([]) -> [];
reverse([X|Xs]) -> reverse(Xs) ++ [X].
find(_, []) -> not_found;
find(X, [X|_]) -> {found, X};
find(X, [_|Ys]) -> find(X, Ys).
delete(_, []) -> [];
delete(X, [X|Ys]) -> Ys;
delete(X, [Y|Ys]) -> [Y|delete(X, Ys)].
flatten([]) -> [];
flatten([Xs|Ys]) -> Xs ++ flatten(Ys).
square1([]) -> [];
square1([X|Xs]) -> [X*X | square1(Xs)].

square2(Xs) -> [X*X || X <- Xs].

square3(Xs) -> lists:map(fun(X) -> X*X end, Xs).
filter1(_, []) -> [];
filter1(F, [X|Xs]) ->
  case F(X) of
    true -> [X|filter1(F, Xs)] ;
    false -> filter1(F, Xs)
  end.

filter2(_, []) -> [];
filter2(F, [X|Xs]) ->
  Result = F(X),
  if
    Result -> [X|filter2(F, Xs)] ;
    true   -> filter2(F, Xs)
  end.

filter3(F, Xs) -> [X || X <- Xs, F(X)].

Simple message passing

avg_server1(Avg) ->
  io:fwrite("Current average is ~p~n", [Avg]),
  receive
    Num -> avg_server1((Avg + Num) / 2)
  end.
avg_server2() ->
  receive
    Num -> avg_server2([Num])
  end.
avg_server2(Nums) ->
  io:fwrite("The average of ~p is ~p~n", [Nums, sum(Nums) / length(Nums)]),
  receive
    Num -> avg_server2(Nums ++ [Num])
  end.
sum([]) -> 0;
sum([X|Xs]) -> X + sum(Xs).
% Main server function
queue_server(Q) ->
  receive
    {Pid, push, Val} -> Pid ! ok, queue_server(Q ++ [Val]) ;
    {Pid, pop} when length(Q) > 0 -> Pid ! hd(Q), queue_server(tl(Q))
  end.

% API
new_queue() -> spawn(fun() -> queue_server([]) end).
push(Pid, Val) ->
  Pid ! {self(), push, Val},
  receive ok -> ok end.
pop(Pid) ->
  Pid ! {self(), pop},
  receive Val -> Val end.

Semaphores in Erlang

Solution to Q1:

-module(sem).
-export([createSem/1, acquire/1, release/1]).

body(Val) ->
  receive
    {acquire, Pid} when Val > 0 ->
      Pid ! ok,
      body(Val - 1) ;
    release ->
      body(Val + 1)
  end.

createSem(InitialValue) ->
  spawn(fun() -> body(InitialValue) end).

acquire(Semaphore) ->
  Semaphore ! {acquire, self()},
  receive
    ok -> ok
  end.

release(Semaphore) ->
  Semaphore ! release,
  ok.

Solution to Q2:

-module(semtester).
-export([test/0]).

testN(N, Sem) ->
  sem:acquire(Sem),
  io:fwrite("~p in~n", [N]),
  timer:sleep(500),
  io:fwrite("~p out~n", [N]),
  sem:release(Sem),
  testN(N, Sem).

test() ->
  Sem = sem:createSem(1),
  lists:foreach(
    fun(N) -> spawn(fun() -> testN(N, Sem) end) end,
    lists:seq(1,5)
  ).

Elevator

Solution to Q1:

New function loop/1 needs to be defined, while the definition of loop/0 needs to be changed to call loop/1.

loop() -> loop([]).

loop(Buffer) when length(Buffer) >= 10 ->
  net_io:transmit(Buffer),
  loop([]);
loop(Buffer) ->
  receive
    {request, Pid, Ref, {send, Msg}} ->
      Pid ! {result, Ref, ok},
      loop(Buffer ++ [Msg])
  end.

Solution to Q2:

The definitions of the loop/0 and loop/1 should be replaced with the following definitions of loop/0 and loop/2.

loop() ->
  receive
    {request, Pid, Ref, {send, Msg}} ->
      Pid ! {result, Ref, ok},
      Self = self(),
      RefT = make_ref(),
      spawn(fun () ->
        receive after 100 -> Self!{timeout, RefT} end
      end),
      loop([Msg], RefT)
  end.

loop(Buffer, _) when length(Buffer) >= 10 ->
  transmit(Buffer),
  loop();
loop(Buffer, RefT) ->
  receive
    {request, Pid, Ref, {send, Msg}} ->
      Pid ! {result, Ref, ok},
      loop(Buffer ++ [Msg], RefT);
    {timeout, RefT} ->
      transmit(Buffer),
      loop()
  end.

Here make_ref() is used to make sure that we do not receive old timeout messages. This might be handled in some other way, but it is required to address this problem.

Menu