### 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]),
Num -> avg_server1((Avg + Num) / 2)
end.``````
``````avg_server2() ->
Num -> avg_server2([Num])
end.
avg_server2(Nums) ->
io:fwrite("The average of ~p is ~p~n", [Nums, sum(Nums) / length(Nums)]),
Num -> avg_server2(Nums ++ [Num])
end.
sum([]) -> 0;
sum([X|Xs]) -> X + sum(Xs).``````
``````% Main server function
queue_server(Q) ->
{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},
pop(Pid) ->
Pid ! {self(), pop},

### Semaphores in Erlang

Solution to Q1:

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

body(Val) ->
{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()},
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) ->
{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() ->
{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) ->
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.