Last active
July 6, 2020 21:15
-
-
Save elbrujohalcon/8d3366fe1765c63a3e48d6d5589f1391 to your computer and use it in GitHub Desktop.
Palindrome
This file contains hidden or 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([test/0]). | |
-export([server/0]). | |
-export([start/0, check/2, stop/1]). | |
test() -> | |
Checks = [{"Abba", true}, | |
{"baba", false}, | |
{"Yo hago yoga hoy", true}, | |
{"Yo haré yoga mañana", false}, | |
{"Acaso hubo buhos aca", true}, | |
{"Acaso habra buhos aqui", false}, | |
{"", true}, | |
{"...", true}], | |
Server = palin:start(), | |
ok = lists:foreach(fun ({I, _}) -> | |
start_test_client(self(), Server, I) | |
end, | |
Checks), | |
ok = lists:foreach(fun ({I, O}) -> | |
{I, O} = {I, check_test_client(I)} | |
end, | |
Checks), | |
stop = palin:stop(Server), | |
ok. | |
start_test_client(Caller, Server, Input) -> | |
spawn(fun () -> | |
Output = palin:check(Server, Input), | |
Caller ! {Input, Output} | |
end). | |
check_test_client(Input) -> | |
receive | |
{Input, Output} -> | |
Output | |
end. | |
%% API ------------------------------------------------------------------------- | |
start() -> | |
spawn(palin, server, []). | |
check(Server, String) -> | |
Server ! {check, self(), String}, | |
receive | |
X -> | |
X | |
end. | |
stop(Server) -> | |
Server ! stop. | |
%% SERVER ---------------------------------------------------------------------- | |
server() -> | |
receive | |
{check, Caller, String} -> | |
Caller ! pal_check(String), | |
server(); | |
stop -> | |
ok | |
end. | |
%% SERVER INTERNALS ------------------------------------------------------------ | |
rem_punct(String) -> | |
lists:filter(fun (Ch) -> | |
not lists:member(Ch, "\"'\t\n ") | |
end, | |
String). | |
to_small(String) -> | |
lists:map(fun (Ch) -> | |
case $A =< Ch andalso Ch =< $Z of | |
true -> | |
Ch + 32; | |
false -> | |
Ch | |
end | |
end, | |
String). | |
pal_check(String) -> | |
Normalise = to_small(rem_punct(String)), | |
lists:reverse(Normalise) == Normalise. |
This file contains hidden or 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). | |
%% Tests | |
-export([test/0]). | |
%% Server API | |
-export([server/0, server/1]). | |
%% Client API | |
-export([start/1, check/2, stop/1]). | |
%% @doc Runs the tests | |
test() -> | |
Checks = [{"Abba", true}, | |
{"baba", false}, | |
{"Yo hago yoga hoy", true}, | |
{"Yo haré yoga mañana", false}, | |
{"Acaso hubo buhos aca", true}, | |
{"Acaso habra buhos aqui", false}, | |
{"", true}, | |
{"...", true}], | |
Server = palin:start(3), | |
ok = lists:foreach(fun ({I, _}) -> | |
start_test_client(self(), Server, I) | |
end, | |
Checks), | |
ok = lists:foreach(fun ({I, O}) -> | |
{I, O} = {I, check_test_client(I)} | |
end, | |
Checks), | |
stop = palin:stop(Server), | |
ok. | |
start_test_client(Caller, Server, Input) -> | |
spawn(fun () -> | |
Output = palin:check(Server, Input), | |
Caller ! {Input, Output} | |
end). | |
check_test_client(Input) -> | |
receive | |
{Input, Output} -> | |
Output | |
end. | |
%% API ------------------------------------------------------------------------- | |
%% @doc Boots up the system with N servers to handle requests. | |
%% Returns the Pid of the broker that users should use for other API calls. | |
-spec start(pos_integer()) -> pid(). | |
start(Servers) -> | |
spawn(palin, server, [Servers]). | |
%% @doc Boots up the system with N servers to handle requests. | |
%% Sends a request for palindrome-checking to the broker. | |
%% The request will then be processed by a server and the answer will be | |
%% sent back to this client process. | |
%% That answer is then returned. | |
-spec check(pid(), string()) -> boolean(). | |
check(Server, String) -> | |
% Sent a request to the server, including the client Pid so the server knows | |
% where to send the response | |
Server ! {check, self(), String}, | |
% Wait for a response from the server and | |
receive | |
X -> | |
X % use it as the result of this function | |
end. | |
%% @doc Sends the stop signal to the broker, therefore stopping the whole system | |
-spec stop(pid()) -> stop. | |
stop(Server) -> | |
Server ! stop. | |
%% SERVER ---------------------------------------------------------------------- | |
%% @doc Starts the broker, which is a process that will loop until it gets a | |
%% 'stop' message, distributing the requests in a round-robin fashion | |
%% among the ServerCount servers. | |
-spec server(pos_integer()) -> ok. | |
server(ServerCount) -> | |
% Start each of the servers | |
Servers = [spawn(palin, server, []) || _ <- lists:seq(1, ServerCount)], | |
% Evaluate the recursive broker/1 function to receive messages | |
broker(Servers). | |
%% @doc The broker loop. It loops until it gets a 'stop' message. | |
%% Each {check, pid(), string()} message that it receives is delivered to | |
%% the first available server. | |
%% The return type of this function is 'ok' since it terminates after | |
%% evaluating lists:foreach/2. | |
-spec broker([pid()]) -> ok. | |
broker([Server | OtherServers] = Servers) -> | |
receive | |
{check, Caller, String} -> | |
% check command is sent to the first server | |
Server ! {check, Caller, String}, | |
% we don't wait for a response here, just update the state and keep looping | |
broker(OtherServers ++ [Server]); | |
stop -> | |
% turn off all the servers and return | |
lists:foreach(fun (S) -> | |
S ! stop | |
end, | |
Servers) | |
end. | |
%% @doc Loops until it gets a 'stop' message from the broker. | |
%% Each {check, pid(), string()} message that it receives is processed and | |
%% the result is sent to the caller. | |
%% The return type of this function is 'ok' since it terminates receiving | |
%% stop. | |
-spec server() -> ok. | |
server() -> | |
receive | |
{check, Caller, String} -> | |
Result = pal_check(String), | |
% instrumentation to verify that everything is working as expected | |
io:format("~p checked ~s for ~p: ~p~n", [self(), String, Caller, Result]), | |
% the result is sent back to the original caller | |
Caller ! Result, | |
% the server keeps looping | |
server(); | |
stop -> | |
ok | |
end. | |
%% SERVER INTERNALS ------------------------------------------------------------ | |
rem_punct(String) -> | |
lists:filter(fun (Ch) -> | |
not lists:member(Ch, "\"'\t\n ") | |
end, | |
String). | |
to_small(String) -> | |
lists:map(fun (Ch) -> | |
case $A =< Ch andalso Ch =< $Z of | |
true -> | |
Ch + 32; | |
false -> | |
Ch | |
end | |
end, | |
String). | |
pal_check(String) -> | |
Normalise = to_small(rem_punct(String)), | |
lists:reverse(Normalise) == Normalise. |
This file contains hidden or 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([test/0]). | |
-export([server/1]). | |
-export([start/0, check/2, stop/1]). | |
test() -> | |
Server = palin:start(), | |
true = palin:check(Server, "Abba"), | |
false = palin:check(Server, "baba"), | |
stop = palin:stop(Server), | |
ok. | |
%% API ------------------------------------------------------------------------- | |
start() -> | |
spawn(palin, server, [self()]). | |
check(Server, String) -> | |
Server ! {check, String}, | |
receive X -> X end. | |
stop(Server) -> | |
Server ! stop. | |
%% SERVER ---------------------------------------------------------------------- | |
server(Caller) -> | |
receive | |
{check, String} -> | |
Caller ! pal_check(String), | |
server(Caller); | |
stop -> | |
ok | |
end. | |
%% SERVER INTERNALS ------------------------------------------------------------ | |
rem_punct(String) -> | |
lists:filter(fun (Ch) -> | |
not lists:member(Ch, "\"'\t\n ") | |
end, | |
String). | |
to_small(String) -> | |
lists:map(fun (Ch) -> | |
case $A =< Ch andalso Ch =< $Z of | |
true -> | |
Ch + 32; | |
false -> | |
Ch | |
end | |
end, | |
String). | |
pal_check(String) -> | |
Normalise = to_small(rem_punct(String)), | |
lists:reverse(Normalise) == Normalise. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment