Search code examples
concurrencyerlangspawnerlspawning

Erlang newbie - concurrency and message passing


I'm still new to programming and brand new erlang (2 week newbie!). I edited slightly so atleast it'll compile and run. But I still can't figure out the concept of sending the results to a "joiner process" to join all the seperate results.

It does split and send the "chunks" an received to count the chunks. Just don't know how to get all those processes to join their individual results. I sort of understand the concept below, but have no idea how that's implimented. I've been trying for many days and hours to get it to this point, but can't get it to do anything without getting errors or unbound variables, etc.

-module (ccharcount1d).
-compile(export_all).

load(F)->
 {ok, Bin} = file:read_file(F),
  List=binary_to_list(Bin),
  Ls=string:to_lower(List),
  Length=round(length(List)/20),
  Collect_Results = spawn(ccharcount1d, collect_results, []),

  Sl=split(Ls,Length),

  io:fwrite("Loaded, Split, and sent to multiple processes~n").




%%splits txt file into "chunks" and sends those "chunks" to be processed 
split([],_)->[];
split(List,Length)->
S1=string:substr(List,1,Length),
case length(List) > Length of
   true->S2=string:substr(List,Length+1,length(List)),
   Process_Split = spawn(ccharcount1d,receive_splits,[]),
   Process_Split ! {self(), S1};

   false->S2=[],
   Process_Split = spawn(ccharcount1d,receive_splits,[]),
   Process_Split ! {self(), S1}   

 end,  

[S1]++split(S2,Length).


%%recieves the split "chunks" and counts the results 
receive_splits()-> 
    receive
        {From, S1} -> 
            Result=go(S1)
            %Collect_Results ! Result
    end.



collect_results()-> 
    receive
        {Process_Split, Result} ->
            Result=join([],Result)
    end.



join([],[])->[];
join([],R)->R;
join([H1 |T1],[H2|T2])->
{C,N}=H1,
{C1,N1}=H2,
[{C1,N+N1}]++join(T1,T2).



count(Ch, [],N)->N;
count(Ch, [H|T],N) ->
   case Ch==H of
   true-> count(Ch,T,N+1);
   false -> count(Ch,T,N)
end.

go(L)->
Alph=[$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v,$w,$x,$y,$z],
rgo(Alph,L,[]).

rgo([H|T],L,Result)->
N=count(H,L,0),
Result2=Result++[{[H],N}],
rgo(T,L,Result2);


rgo([],L,Result)-> Result.

Solution

  • again, i'm new. I'm understanding the concept. I'm not understanding the syntax. the how to "pass a Pid to a worker process"

    start() ->
        Work = ...,
        JoinPid = spawn(fun() -> join_func([]) end),  
        WorkerPid = spawn(fun() -> worker_func(JoinPid, Work) end),  %Pass JoinPid to worker process.
        ...
    
    join_func(Acc) ->
        receive
            Result ->
                join_func([Result|Acc]);  %Recursive function call--the life blood of all functional languages.
    
            ...
        end
    
    worker_func(JoinPid, Work) ->
        Result = ... Work ...,
        JoinPid ! Result.  %Worker process uses JoinPid to send back the results.
    

    Also, check out this:

    8> [$a, $b, $c].
    "abc"
    
    9> "abc".
    "abc"
    

    The output shows that [$a, $b, $c] is equivalent to "abc". That means you can write this:

    [$a,$b,$c,$d,$e,$f,$g,$h,$i,$j,$k,$l,$m,$n,$o,$p,$q,$r,$s,$t,$u,$v,$w,$x,$y,$z]
    

    much more succinctly like this:

    "abcdefghijklmnopqrstuvwxyz"
    

    and even more so, like this:

    11> lists:seq(97, 122).
    "abcdefghijklmnopqrstuvwxyz"