Erlang: How to pass a path string to a function? - erlang

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>

Related

How to spawn process with arguments from erlang shell

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.

List of tuples to map on Erlang

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}

How exactly Erlang receive expression works?

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

How to document a type as just a name?

Looking at Erlang docs, sometimes I come across type specs, that document a function type without really specifying the type...
Hard to explain, so let me give you an example. In the gen_server the handle_call function shows up as the following in the docs:
Request = term()
From = {pid(),Tag}
State = term()
Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}
| {reply,Reply,NewState,hibernate}
| {noreply,NewState} | {noreply,NewState,Timeout}
| {noreply,NewState,hibernate}
| {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
Reply = term()
NewState = term()
Timeout = int()>=0 | infinity
Reason = term()
Here the type Tag is never shown (i.e. it's just a variable name).
Is the same possible to do with edoc? The closest I found was opaque type spec, but that documents it as abstract - is that the same?
It is possible as long as the argument variable name in the function (in all clauses) and that name used in the #spec are same. For example.
%% #spec start_link(Args) -> {ok, pid()}
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
will generate the following doc
start_link(Args) -> {ok, pid()}
If you have a different name for example
%% #spec start_link(Args) -> {ok, pid()}
start_link(Num) when is_integer(Num) ->
gen_server:start_link(?MODULE, [], []);
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
It would generate as
start_link(Num::Args) -> {ok, pid()}
assuming Args as a type.
I would personally not recommend to use edoc #spec and instead use -spec as they are used by dialyzer and hence can be validated.
edoc can generate the doc from -spec too. Given both -spec and #spec, edoc overrides to #spec directive.
%% #spec start_link(Args) -> {ok, Pid}
-spec start_link(term()) -> {ok, pid()}.
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
Above will result in
start_link(Args) -> {ok, Pid}
And removing #spec from above will result in
start_link(Args::term()) -> {ok, pid()}
As far as I can see, this is not possible with Edoc.
I tried using a spec like this:
-spec foo(Something) -> term().
foo(X) ->
X.
And while Edoc is actually happy about it, and gives the type spec as foo(Something) in the docs without specifying what Something is, the compiler complains about it, and says:
type variable 'Something' is only used once (is unbound)
So you'd have to write:
-spec foo(Something::_) -> term().
foo(X) ->
X.
which shows up as foo(Something::term()), thereby giving a type specification for Something.
Using an Edoc-only type specification:
%% #spec foo(Something) -> term()
foo(X) ->
X.
Edoc treats Something as a type name that applies to the variable X and puts foo(X::Something) in the documentation.
So neither way would do exactly what you want to achieve.

no_proc exception from gen_server

when executing the below code gen_server is raising an exception
-module(drop).
-behaviour(gen_server).
-export([start_link/0]).
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {count}).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
{ok, #state{count=0}}.
handle_call(_Request, _From, State) ->
Distance = _Request,
Reply = {ok, fall_velocity(Distance)},
NewState=#state{ count= State#state.count+1},
{reply, Reply, NewState}.
handle_cast(_Msg, State) ->
io:format("so far, calculated ~w velocities.~n", [State#state.count]),
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).
OUTPUT:
1> gen_server:call(drop, 60).
** exception exit: {noproc,{gen_server,call,[drop,60]}}
in function gen_server:call/2 (gen_server.erl, line 180).
What's wrong in the above code? Do we need to compile the gen_server module after compiling the drop module?
no_proc -- means 'no process' -- you have not started your server.
Gen_server is a part of OTP architecture. It means you need to write application that starts supervisor which starts your drop server.
And then you can call it using gen_server:call
If you need just function to calculate velocity, you actually dont need OTP, you can export and call a function in the module.. Kind of
-module(drop).
-export([fall_velocity/1]).
.....
and then invoke it
drop:fall_velocity(60).
BTW gen_server module is already compiled in the erlang libs.
The code you are testing works fine. As it is already said you need to start the gen_server. Here is the way to do it, and then ask some request:
1> c(drop).
{ok,drop}
2> S = spawn(drop,start_link,[]).
<0.40.0>
3> registered().
[rex,net_sup,inet_db,kernel_sup,global_name_server,
code_server,file_server_2,init,kernel_safe_sup,
application_controller,user,error_logger,user_drv,
standard_error,global_group,standard_error_sup,drop,auth,
erl_epmd,net_kernel,erl_prim_loader]
4> gen_server:call(drop,25).
{ok,22.135943621178658}
5> gen_server:call(drop,13).
{ok,15.962455951387932}
6> gen_server:call(drop,20).
{ok,19.79898987322333}
7> gen_server:cast(drop,what).
so far, calculated 3 velocities.
ok
command 1 compiles the module. There is no need to compile the gen_server, it is already done in the Erlang libraries.
command 2 start the gen_server, generally in a module like drop, you add some interface function that hide this call something like start() -> spawn(?MODULE,start_link,[]). so you can start the server with simple call drop:start()
command 3 shows that the new process whas registered whith the name drop.
commands 4,5 and 6 ask for a velocity evaluation. As for start, the usage is to have an interface function such as velocity(N) -> gen_server:call(?MODULE,N) so you can simply call drop:velocity(25) the usage is also to "decorate" the message so you will be able to have more function later
command 7 use the message cast to get the number of velocities evaluated so far. Same remark about interface and decoration. here is a version more compliant with usage:
-module(drop).
-behaviour(gen_server).
%% interfaces
-export([start_link/0,velocity/1,so_far/0]).
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {count}).
%% interfaces
start_link() ->
spawn (gen_server,start_link,[{local, ?SERVER}, ?MODULE, [], []]).
velocity(N) ->
gen_server:call(?MODULE,{get_velocity,N}).
so_far() ->
gen_server:cast(?MODULE,so_far).
%% call back
init([]) ->
{ok, #state{count=0}}.
handle_call({get_velocity,Distance}, _From, State) ->
Reply = {ok, fall_velocity(Distance)},
NewState=#state{ count= State#state.count+1},
{reply, Reply, NewState};
handle_call(Request, _From, State) ->
Reply = io:format("unknown request ~p~n",[Request]),
{reply, Reply, State}.
handle_cast(so_far, State) ->
io:format("so far, calculated ~w velocities.~n", [State#state.count]),
{noreply, State};
handle_cast(Msg, State) ->
io:format("unknown request ~p~n", [Msg]),
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
fall_velocity(Distance) -> math:sqrt(2 * 9.8 * Distance).
and now the commands look simpler:
12> drop:start_link().
<0.60.0>
13> drop:velocity(25).
{ok,22.135943621178658}
14> drop:velocity(20).
{ok,19.79898987322333}
15> drop:velocity(13).
{ok,15.962455951387932}
16> drop:so_far().
so far, calculated 3 velocities.
ok
You need to start your server before being able to interact with it via gen_server:call/2.
drop:start_link().

Resources