I have a list of tuples like this:[{key,val},{key2,val2}...] I want to be able to convert it into a map:
#{key=>val, key2=>val2 ......}
You can use the from_list function from the maps module:
maps:from_list(Yourlist).
And if Hendri's solution is too simple for you, then you can do this:
-module(my).
-compile(export_all).
create_map(List_Of_Key_Val_Tuples) ->
create_map(List_Of_Key_Val_Tuples, #{}).
create_map([], Acc) ->
Acc;
create_map([{Key, Val} | Tail], Acc) ->
create_map(Tail, Acc#{Key => Val}).
In the shell:
11> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
12> my:create_map([{a, 10}, {"hello", hi}, {fun(X) -> X+2 end, add_two}]).
#{a => 10,#Fun<erl_eval.6.99386804> => add_two,"hello" => hi}
Related
I created a new file, based on OTP gen_server behaviour.
This is the begining of it:
-module(appender_server).
-behaviour(gen_server).
-export([start_link/1, stop/0]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link(filePath) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, filePath, []).
init(filePath) ->
{ok, theFile} = file:open(filePath, [append]). % File is created if it does not exist.
...
The file compiled ok using c(appender_server).
When I try to call start_link function from the shell, like this:
appender_server:start_link("c:/temp/file.txt").
I get:
** exception error: no function clause matching appender_server:start_link("c:/temp/file.txt") (appender_server.erl,
line 10)
What do I do wrong?
filePath is an atom--not a variable:
7> is_atom(filePath).
true
In erlang, variables start with a capital letter. The only way erlang could match your function clause would be to call the function like this:
appender_server:start_link(filePath)
Here is an example:
-module(a).
-compile(export_all).
go(x) -> io:format("Got the atom: x~n");
go(y) -> io:format("Got the atom: y~n");
go(X) -> io:format("Got: ~w~n", [X]).
In the shell:
3> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
4> a:go(y).
Got the atom: y
ok
5> a:go(x).
Got the atom: x
ok
6> a:go(filePath).
Got: filePath
ok
7> a:go([1, 2, 3]).
Got: [1,2,3]
ok
8>
I do not know what overload of spawn to use when launching a process from the erlang shell , since i need to pass arguments.
A=spawn(
fun(TID)->
receive {FROM,MSG}->
FROM ! {self(),MSG}
after 0 ->
TID !{self(),timeouted}
end
end,
TID
).
There is no overload for just the function and arguments.
What is the module name when launching from shell ?
I have also tried:
A=spawn(?MODULE,fun()->....,TID).
P.S
In my case as you can see i need to provide arguments to the spawn method , while running it directly from the erlang shell.
Just embed the definition in a fun:
A = fun(X) ->
TID = X,
spawn(
fun()->
receive {FROM,MSG}->
FROM ! {self(),MSG}
after 0 ->
TID !{self(),timeouted}
end
end
)
end.
and then you can use A(YourParam).
Typically, you define a function in a module:
-module(a).
-compile(export_all).
go(X)->
receive {From, Msg}->
From ! {self(), Msg}
after 0 ->
io:format("~s~n", [X])
end.
Then do this:
9> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
10> Pid = spawn(a, go, ["hello"]).
hello
<0.95.0>
Defining functions in the shell is too much of a pain in the ass.
Response to comment:
Here's how you can do simple testing in erlang:
-module(a).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
do(Y) ->
Y.
go(X)->
receive {From, Msg}->
From ! {self(), Msg}
after 0 ->
X
end.
do_test() ->
10 = do(10).
go_test() ->
"hello" = go("hello").
In the shell:
1> c(a).
2> a:test().
2 tests passed.
ok
Here's what happens when a test fails:
5> a:test().
a: go_test...*failed*
in function a:go_test/0 (a.erl, line 18)
**error:{badmatch,"hello"}
output:<<"">>
=======================================================
Failed: 1. Skipped: 0. Passed: 1.
error
6>
You don't even need to use eunit because you can simply do:
go_test() ->
"hello" = go("hello").
Then in the shell:
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
2> a:go_test().
You'll get a bad match error if go("hello") doesn't return "hello":
** exception error: no match of right hand side value "hello"
in function a:go_test/0 (a.erl, line 18)
The advantage of using eunit is that with one command, a:test(), you can execute all the functions in the module that end in _test.
I am trying to create multiple processes in Erlang. For each key in the map, I want to create a process.
I have tried using the fold operation. Below is the code snippet for the same:
CreateMultipleThreads = fun(Key,Value,ok) ->
Pid = spawn(calculator, init_method, [Key,Value,self()])
end,
maps:fold(CreateMultiplThreads,[],Map).
When maps:fold(CreateMultiplThreads,[],Map) is executed, the program terminates with the following error :
init terminating in do_boot.
init terminating in do_boot is not your problem. This just means that something caused your node to fail to start. Erlang has a habit of printing out lots of error messages. Your actual error is probably a few lines (or even lots of lines) above this. Look there first.
With that said, I tried your code directly in the erl shell:
$ erl
1> CreateMultipleThreads =fun(Key,Value,ok)-> Pid = spawn(calculator, init_method, [Key,Value,self()]) end.
#Fun<erl_eval.18.128620087>
2> Map = #{k1 => v1, k2 => v2}.
#{k1 => v1,k2 => v2}
3> maps:fold(CreateMultipleThreads,[],Map).
** exception error: no function clause matching erl_eval:'-inside-an-interpreted-fun-'(k1,v1,[])
in function erl_eval:eval_fun/6 (erl_eval.erl, line 829)
in call from maps:fold_1/3 (maps.erl, line 257)
What this is trying to tell you is that the function that you passed to maps:fold doesn't match the expected form -- no function clause matching <mangled-name> (k1,v1,[]).
It's attempting to pass (k1, v1, []), but your function is expecting (Key, Value, ok). The [] doesn't match the ok.
Where did the [] come from? It came from the accumulator value you initially passed to maps:fold. On each iteration, the previous result is passed as the new accumulator, so you need to think about how to keep it all matching.
If you genuinely don't want the result, just pass ok as the initial accumulator value, match ok, and make sure to return ok:
CreateMultipleThreads = fun(Key, Value, ok) ->
Pid = spawn(calculator, init_method, [Key, Value, self()]),
ok
end.
maps:fold(CreateMultipleThreads, ok, Map).
Or you can do something useful with the accumulator, such as collect the process IDs:
Map = #{k1 => v1, k2 => v2},
CreateMultipleThreads = fun(Key, Value, Acc)->
Pid = spawn(calculator, init_method, [Key, Value, self()])
[Pid | Acc]
end,
Pids = maps:fold(CreateMultipleThreads, [], Map),
Pids.
Obviously, I can't actually test this, because calculator:init_method/3 doesn't exist for me, but you get the idea, hopefully.
init terminating in do_boot
Searching around for similar errors, it looks like that error could be caused by improper command line arguments or your file name conflicts with an erlang file name. Therefore, you would need to post how you are running your program.
Below is a working example that you might be able to adapt to your situation--including how to run it:
calculator.erl:
-module(calculator).
-compile(export_all).
init(X, Y, Pid) ->
io:format("init() in Process ~w got args ~w, ~w, ~w~n",
[self(), X, Y, Pid]).
my.erl:
-module(my).
-compile([export_all]).
go() ->
FoldFunc = fun(Key, Value, Acc) ->
Pid = spawn(calculator, init, [Key, Value, self()]),
[Pid|Acc] % Returns new value for Acc
end,
Map = #{a => 3, b => 7, c => 10},
_Pids = maps:fold(FoldFunc, [], Map). % [] is the initial value for Acc.
When you call a fold function, e.g. lists:foldl(), lists:foldr(), maps:fold(), you iterate over each value in a collection, like a list or map, and perform some operation with each value, then you accumulate the results of those operations, and the fold function returns the accumulated results.
In the shell:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> c(calculator).
calculator.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,calculator}
3> Calculators = my:go().
init() in Process <0.80.0> got args a, 3, <0.64.0>
init() in Process <0.81.0> got args b, 7, <0.64.0>
init() in Process <0.82.0> got args c, 10, <0.64.0>
[<0.82.0>,<0.81.0>,<0.80.0>] %Return value of my:go()
4>
The reason you might want to accumulate the pids of the spawned processes is to receive messages that are tagged with the pids of the spawned processes. For instance, if you want to get results from each of the calculators, you might use a receive clause like this:
Pid = % One of the calculator pids
receive
{Pid, Result} ->
%Do something with result
where each calculator does this:
Pid ! {self(), Result}
Something like this:
calculator.erl:
-module(calculator).
-compile(export_all).
init(X, Y, Pid) ->
io:format("init() in Process ~w got args ~w, ~w, ~w~n",
[self(), X, Y, Pid]),
RandNum = rand:uniform(5), % time it takes to perform calc
timer:sleep(RandNum * 1000), % sleep 1-5 seconds
Pid ! {self(), RandNum}. % send back some result
my.erl:
-module(my).
-compile([export_all]).
go() ->
FoldFunc = fun(Key, Value, Acc) ->
Pid = spawn(calculator, init, [Key, Value, self()]),
[Pid|Acc]
end,
Map = #{a => 3, b => 7, c => 10},
Calculators = maps:fold(FoldFunc, [], Map),
lists:foreach(fun(Calculator) ->
receive
{Calculator, Result} ->
io:format("Result from ~w is: ~w~n", [Calculator, Result])
end
end,
Calculators
).
In the shell:
7> c(calculator).
calculator.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,calculator}
8> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
9> my:go().
init() in Process <0.107.0> got args a, 3, <0.64.0>
init() in Process <0.108.0> got args b, 7, <0.64.0>
init() in Process <0.109.0> got args c, 10, <0.64.0>
Result from <0.109.0> is: 5
Result from <0.108.0> is: 4
Result from <0.107.0> is: 3
ok
Why receive expression is sometimes called selective receive?
What is the "save queue"?
How the after section works?
There is a special "save queue" involved in the procedure that when you first encounter the receive expression you may ignore its presence.
Optionally, there may be an after-section in the expression that complicates the procedure a little.
The receive expression is best explained with a flowchart:
receive
pattern1 -> expressions1;
pattern2 -> expressions2;
pattern3 -> expressions3
after
Time -> expressionsTimeout
end
Why receive expression is sometimes called selective receive?
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
start() ->
spawn(my, go, []).
go() ->
receive
{xyz, X} ->
io:format("I received X=~w~n", [X])
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Pid = my:start().
<0.79.0>
3> Pid ! {hello, world}.
{hello,world}
4> Pid ! {xyz, 10}.
I received X=10
{xyz,10}
Note how there was no output for the first message that was sent, but there was output for the second message that was sent. The receive was selective: it did not receive all messages, it received only messages matching the specified pattern.
What is the "save queue"?
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
start() ->
spawn(my, go, []).
go() ->
receive
{xyz, X} ->
io:format("I received X=~w~n", [X])
end,
io:format("What happened to the message that didn't match?"),
receive
Any ->
io:format("It was saved rather than discarded.~n"),
io:format("Here it is: ~w~n", [Any])
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Pid = my:start().
<0.79.0>
3> Pid ! {hello, world}.
{hello,world}
4> Pid ! {xyz, 10}.
I received X=10
What happened to the message that didn't match?{xyz,10}
It was saved rather than discarded.
Here it is: {hello,world}
How the after section works?
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
start() ->
spawn(my, go, []).
go() ->
receive
{xyz, X} ->
io:format("I received X=~w~n", [X])
after 10000 ->
io:format("I'm not going to wait all day for a match. Bye.")
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Pid = my:start().
<0.79.0>
3> Pid ! {hello, world}.
{hello,world}
I'm not going to wait all day. Bye.4>
Another example:
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
sleep(X) ->
receive
after X * 1000 ->
io:format("I just slept for ~w seconds.~n", [X])
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:sleep(5).
I just slept for 5 seconds.
ok
For the following fragment:
outer_func(State) ->
spawn(fun()-> do_something(State) end).
Will State be shared or deep-copied to the spawned process heap?
It will be deep copied. Here's a simple demo:
1> State = lists:seq(1, 1000000).
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29|...]
2> DoSomething = fun(State) -> io:format("~p~n", [process_info(self(), memory)]) end.
3> spawn(fun() -> DoSomething(State) end), spawn(fun() -> DoSomething(State) end), spawn(fun() -> DoSomething(State) end).
{memory,16583520}
{memory,16583520}
{memory,16583520}
In contrast to that, here's the output when the state is a large binary which is never "deep" copied when shared with multiple processes:
1> State = binary:copy(<<"a">>, 50000000).
<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"...>>
2> DoSomething = fun(State) -> io:format("~p~n", [process_info(self(), memory)]) end.
3> spawn(fun() -> DoSomething(State) end), spawn(fun() -> DoSomething(State) end), spawn(fun() -> DoSomething(State) end).
{memory,8744}
{memory,8744}
{memory,8744}
So a process with a list of integers from 1 to 1 million used about 16MB of memory while the one with a large binary used 8KB (the binary should actually be a negligible part of that).