Last active
April 4, 2017 16:02
-
-
Save lucasdf/be9d13e8088857c1783f02be8d47c7c9 to your computer and use it in GitHub Desktop.
Exercises for Week 1 of the course Concurrent Programming in Erlang.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Concurrent Programming Erlang: https://www.futurelearn.com/courses/concurrent-programming-erlang |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% Based on code from | |
%% Erlang Programming | |
%% Francecso Cesarini and Simon Thompson | |
%% O'Reilly, 2008 | |
%% http://oreilly.com/catalog/9780596518189/ | |
%% http://www.erlangprogramming.org/ | |
%% (c) Francesco Cesarini and Simon Thompson | |
-module(frequency). | |
-export([init/0, start_server/0]). | |
% Usage: | |
% 1> frequency:start_server(). | |
% true | |
% 2> frequency ! {request, self(), allocate}. | |
% {request,<0.58.0>,allocate} | |
% 3> receive {reply, Reply} -> Reply end. | |
% {ok,10} | |
start_server() -> | |
register(?MODULE, spawn(?MODULE, init, [])). | |
%% These are the start functions used to create and | |
%% initialize the server. | |
init() -> | |
Frequencies = {get_frequencies(), []}, | |
loop(Frequencies). | |
% Hard Coded | |
get_frequencies() -> [10,11,12,13,14,15]. | |
%% The Main Loop | |
loop(Frequencies) -> | |
receive | |
{request, Pid, allocate} -> | |
io:format("Allocate request~n"), | |
io:format("Frequencies list before processing: ~p~n", [Frequencies]), | |
{NewFrequencies, Reply} = allocate(Frequencies, Pid), | |
io:format("Frequencies list after processing: ~p~n~n", [NewFrequencies]), | |
Pid ! {reply, Reply}, | |
loop(NewFrequencies); | |
{request, Pid , {deallocate, Freq}} -> | |
io:format("Deallocate request: ~p~n", [Freq]), | |
io:format("Frequencies list before processing: ~p~n", [Frequencies]), | |
{NewFrequencies, Reply} = deallocate(Frequencies, Freq, Pid), | |
io:format("Frequencies list after processing: ~p~n~n", [NewFrequencies]), | |
Pid ! {reply, Reply}, | |
loop(NewFrequencies); | |
{request, Pid, stop} -> | |
Pid ! {reply, stopped} | |
end. | |
%% The Internal Help Functions used to allocate and | |
%% deallocate frequencies. | |
allocate({[], Allocated}, _Pid) -> | |
{{[], Allocated}, {error, no_frequency}}; | |
allocate({[Freq|Free], Allocated}, Pid) -> | |
case already_allocated(Allocated, Pid) of | |
true -> | |
{ {[Freq|Free], Allocated}, {error, already_allocated}}; | |
false -> | |
{{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}} | |
end. | |
deallocate({Free, Allocated}, Freq, Pid) -> | |
case pid_has_frequency(Allocated, Pid, Freq) of | |
true -> | |
NewAllocated=lists:keydelete(Freq, 1, Allocated), | |
{ {[Freq|Free], NewAllocated}, ok}; | |
false -> | |
{ {Free, Allocated}, {error, not_allocated}} | |
end. | |
% already_allocated returns: | |
% true: Pid has been allocated a frequency | |
% false: Pid has not been allocated a frequency | |
% Maybe a better solution could be to have a separated list containing only Pid who have been allocated a frequency or to invert and use {Pid, Frequency} instead of {Frequency, Pid}. | |
already_allocated([], _Pid) -> | |
% If no frequency has been allocated (first parameter is an empty list) then this Pid has not been allocated any frequency. | |
false; | |
already_allocated(Allocated, Pid) -> | |
Pred = fun({_, APid}) -> APid =:= Pid end, | |
case lists:any(Pred, Allocated) of | |
true -> true; | |
false -> false | |
end. | |
% pid_has_frequency returns: | |
% true: Pid has been allocated the frequency Frequency | |
% false: Pid has not been allocated the frequency Frequency | |
pid_has_frequency(Allocated, Pid, Frequency) -> | |
Pred = fun({AFrequency, APid}) -> (APid =:= Pid) and (AFrequency =:= Frequency) end, | |
case lists:any(Pred, Allocated) of | |
true -> true; | |
false -> false | |
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% Based on code from | |
%% Erlang Programming | |
%% Francecso Cesarini and Simon Thompson | |
%% O'Reilly, 2008 | |
%% http://oreilly.com/catalog/9780596518189/ | |
%% http://www.erlangprogramming.org/ | |
%% (c) Francesco Cesarini and Simon Thompson | |
-module(frequency_assignment). | |
-export([start/0,allocate/0,deallocate/1,stop/0]). | |
-export([init/0]). | |
%% These are the start functions used to create and | |
%% initialize the server. | |
start() -> | |
register(frequency_assignment, | |
spawn(frequency_assignment, init, [])). | |
init() -> | |
Frequencies = {get_frequencies(), []}, | |
loop(Frequencies). | |
% Hard Coded | |
get_frequencies() -> [10,11,12,13,14,15]. | |
%% The Main Loop | |
loop(Frequencies) -> | |
receive | |
{request, Pid, allocate} -> | |
timer:sleep(5200), | |
{NewFrequencies, Reply} = allocate(Frequencies, Pid), | |
Pid ! {reply, Reply}, | |
loop(NewFrequencies); | |
{request, Pid , {deallocate, Freq}} -> | |
timer:sleep(5200), | |
NewFrequencies = deallocate(Frequencies, Freq), | |
Pid ! {reply, ok}, | |
loop(NewFrequencies); | |
{request, Pid, stop} -> | |
timer:sleep(5200), | |
Pid ! {reply, stopped} | |
end. | |
%% Functional interface | |
allocate() -> | |
clear(), | |
frequency_assignment ! {request, self(), allocate}, | |
receive | |
{reply, Reply} -> Reply | |
after 5000 -> | |
timeout | |
end. | |
deallocate(Freq) -> | |
clear(), | |
frequency_assignment ! {request, self(), {deallocate, Freq}}, | |
receive | |
{reply, Reply} -> Reply | |
after 5000 -> | |
timeout | |
end. | |
stop() -> | |
clear(), | |
frequency_assignment ! {request, self(), stop}, | |
receive | |
{reply, Reply} -> Reply | |
after 5000 -> | |
timeout | |
end. | |
clear() -> | |
receive | |
Msg -> | |
io:format("Clearing message ~p~n~n",[Msg]), | |
clear() | |
after 0 -> | |
timeout | |
end. | |
%% The Internal Help Functions used to allocate and | |
%% deallocate frequencies. | |
allocate({[], Allocated}, _Pid) -> | |
{{[], Allocated}, {error, no_frequency}}; | |
allocate({[Freq|Free], Allocated}, Pid) -> | |
{{Free, [{Freq, Pid}|Allocated]}, {ok, Freq}}. | |
deallocate({Free, Allocated}, Freq) -> | |
NewAllocated=lists:keydelete(Freq, 1, Allocated), | |
{[Freq|Free], NewAllocated}. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(frequency_test). | |
-export([all/0]). | |
-define(TESTED_MODULE, frequency). | |
% Usage: | |
% 1> frequency_test:all(). | |
all() -> | |
% start the test named process. | |
start_test_server(), | |
% first request to allocate. Should be allocated the frequency 10. | |
test_allocate({reply, {ok, 10}}), | |
% Trying to allocated another frequency. Should receive 'already_allocated' error | |
test_allocate({reply,{error,already_allocated}}), | |
% Trying to deallocate frequency no allocated to this client. Should receive 'not_allocated' error. | |
test_deallocate({reply,{error,not_allocated}}, 11), | |
% Trying to deallocate the frequency allocated before. Should succeed. | |
test_deallocate({reply, ok}, 10), | |
% tests are over, stop the named process. | |
stop_test_server(), | |
tests_success. | |
% test the allocate function on 'frequency' process | |
test_allocate(ExpectedAnswer) -> | |
?TESTED_MODULE ! {request, self(), allocate}, | |
receive | |
ExpectedAnswer -> true; | |
Any -> | |
io:format("Expected ~p ~n", [ExpectedAnswer]), | |
io:format("Got ~p instead ~n", [Any]), | |
exit(tests_not_success) | |
end. | |
% test the deallocate function on 'frequency' process | |
test_deallocate(ExpectedAnswer, Freq) -> | |
?TESTED_MODULE ! {request, self(), {deallocate, Freq}}, | |
receive | |
ExpectedAnswer -> true; | |
Any -> | |
io:format("Expected ~p ~n", [ExpectedAnswer]), | |
io:format("Got ~p instead ~n", [Any]), | |
exit(tests_not_success) | |
end. | |
% start_test_server will start the frequency server for the tests. We check if the 'frequency' process already exists and if it does we kill it and then start a new one. We want to work on a fresh new process to guarantee the tests integrity. | |
start_test_server() -> | |
case whereis(?TESTED_MODULE) of | |
undefined -> | |
% The named process 'frequency' does not exist. Just start a new one. | |
?TESTED_MODULE:start_server(); | |
Pid -> | |
% The named process 'frequency' already exists. Send stop message, unregister it and then start it again. | |
unregister(?TESTED_MODULE), | |
Pid ! {request, self(), stop}, | |
receive | |
{reply, stopped} -> true | |
end, | |
?TESTED_MODULE:start_server() | |
end. | |
% stop_test_server will stop the testing server. | |
stop_test_server() -> | |
case whereis(?TESTED_MODULE) of | |
undefined -> true; | |
Pid -> | |
% The named process 'frequency' already exists. Send stop message, unregister it and then start it again. | |
unregister(?TESTED_MODULE), | |
Pid ! {request, self(), stop}, | |
receive | |
{reply, stopped} -> true | |
end | |
end. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(receiver). | |
-export([receiver/0, receiver2/0]). | |
% Usage example: | |
% Server = spawn(ordered, receiver, []). | |
% 61> Server ! second. | |
% second % The message has not been processed because it is waiting for a message containing atom 'first' | |
% 62> Server ! first. | |
% Processed: first | |
% Processed: second | |
% Another example: | |
% Server = spawn(ordered, receiver, []). | |
% 1> Server ! first. | |
% Processed: first | |
% 2> Server ! first. | |
% The last message won't be processed because the process is waiting for a message containing the atom 'second' | |
receiver() -> | |
receive | |
first -> | |
io:format("Processed: first~n") | |
end, | |
receive | |
second -> | |
io:format("Processed: second~n") | |
end, | |
receiver(). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(palin). | |
-export([palin/1,nopunct/1,palindrome/1, server/0, server/1]). | |
% BEGINNING OF EXERCISE | |
% Simple Server Usage: | |
% 4> Server = spawn(palin, server, [self()]). | |
% <0.71.0> | |
% 5> Server ! {check, "Was it a cat I saw"}. | |
% {check,"Was it a cat I saw"} | |
% 6> flush(). | |
% Shell got {result,"Was it a cat I saw is a palindrome."} | |
% ok | |
server(Pid) -> | |
receive | |
{check, Msg} -> | |
case palindrome(Msg) of | |
true -> | |
Pid ! {result, Msg ++ " is a palindrome."}; | |
false -> | |
Pid ! {result, Msg ++ " is not a palindrome."} | |
end, | |
server(Pid) | |
end. | |
% END OF EXERCISE | |
% palindrome problem | |
% | |
% palindrome("Madam I\'m Adam.") = true | |
palindrome(Xs) -> | |
palin(nocaps(nopunct(Xs))). | |
nopunct([]) -> | |
[]; | |
nopunct([X|Xs]) -> | |
case lists:member(X,".,\ ;:\t\n\'\"") of | |
true -> | |
nopunct(Xs); | |
false -> | |
[ X | nopunct(Xs) ] | |
end. | |
nocaps([]) -> | |
[]; | |
nocaps([X|Xs]) -> | |
[ nocap(X) | nocaps(Xs) ]. | |
nocap(X) -> | |
case $A =< X andalso X =< $Z of | |
true -> | |
X+32; | |
false -> | |
X | |
end. | |
% literal palindrome | |
palin(Xs) -> | |
Xs == reverse(Xs). | |
reverse(Xs) -> | |
shunt(Xs,[]). | |
shunt([],Ys) -> | |
Ys; | |
shunt([X|Xs],Ys) -> | |
shunt(Xs,[X|Ys]). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment