I have a simple car process implemented in Erlang:
-module(cars).
-compile(export_all).
-record(state, {count=1}).
make_car() ->
spawn_link(fun() -> car_proc(#state{}) end).
car_proc(S) ->
receive
{idle, X} ->
io:format("idling for ~p second(s)~n", [X]),
timer:sleep(X*1000);
{move, {X,Y}} ->
io:format("move; x=~p, y=~p~n", [X,Y]);
{stop, Reason} ->
X = S#state.count,
io:format("stopped with count ~p because ~p~n", [X+1, Reason])
end,
X = S#state.count,
car_proc(S#state{count=X+1}).
I can make it idle, but if I call idle twice in a row, it breaks:
59> C = cars:make_car().
<0.207.0>
60> C!{idle,1}.
idling for 1 second(s)
{idle,1}
61> C!{idle,1}.
idling for 1 second(s)
{idle,1}
62>
=ERROR REPORT==== 9-Apr-2013::00:00:00 ===
Error in process <0.207.0> with exit value: {{badmatch,2},[{cars,car_proc,1,[{file,"cars.erl"},{line,20}]}]}
** exception error: no match of right hand side value 2
in function cars:car_proc/1 (cars.erl, line 20)
Why?
The error occurs on line 20, which is
X = S#state.count
It occurs because the pattern matching fails. The variable 'X' is already defined in this line and it's value is 1, because it has been determined in receive block:
receive
{idle, X} ->
In Erlang value of variable can be defined only one time. When you send message {idle, 1} first time X becomes 1 and default value of S#state.count is 1. So in that case 'X' matches S#state.count. When you send {idle, 1} second time X is 1 and S#state.count is 2 (i.e. X and S#state.count are not equal). So you get error in pattern matching. You can use another variable to avoid the problem. Change two last lines
X = S#state.count,
car_proc(S#state{count=X+1}).
to
Count = S#state.count,
car_proc(S#state{count=Count+1}).
and be happy!
Related
I have following code:
M =list:sort([X|Y]), list:sort(length) / 2,io:format("The median of the items is", [M]),
But I get warning when I try to compile it:
Warning: the result of the expression is ignored (suppress the warning by assigning the expression to the _ variable)
What's wrong? How can i fix it?
This is it within my surrounding code and its the only problem with my program. Everything else works.
answer([ ]) -> io:format(" There are no items in the list");
answer([X|Y]) ->
M =list:sort([X|Y]), list:sort(length) / 2,io:format("The median of the items is", [M]),
in your code, list:sort(length) will fail as length is an atom and the function is looking for a list, and the io:format/2 format string is missing a place holder to print the result.
the following code works, al least it prints the results, but it always return ok.
answer([ ]) -> io:format("There are no items in the list~n");
answer(L) when is_list(L) -> io:format("The median of the items is ~p~n",
[lists:nth((length(L)+1) div 2,lists:sort(L))]);
answer(_) -> io:format("error,the input parameter is not a list~n").
some example of use directly entered in the console. You can see that it will give an answer which can seem weird, while technically correct, when the list contains other element than numbers.
1> Answer = fun([ ]) -> io:format("There are no items in the list~n");
1> (L) when is_list(L) -> io:format("The median of the items is ~p~n",
1> [lists:nth((length(L)+1) div 2,lists:sort(L))]);
1> (_) -> io:format("error,the input parameter is not a list~n") end.
#Fun<erl_eval.6.80484245>
2> L1 = [6,9,5,7,8].
[6,9,5,7,8]
3> Answer(L1).
The median of the items is 7
ok
4> L2 = [4,6,3].
[4,6,3]
5> Answer(L2).
The median of the items is 4
ok
6> L3 = [4,6,3,8].
[4,6,3,8]
7> Answer(L3).
The median of the items is 4
ok
8> L4 = [hello, 5,[1,2]].
[hello,5,[1,2]]
9> Answer(L4).
The median of the items is hello
ok
10> Answer("test_string").
The median of the items is 114
ok
11> Answer(test_atom).
error,the input parameter is not a list
ok
12> Answer("").
There are no items in the list
ok
13>
Is there an equivalent expression for the increment/decrement operator e.g. counter++?
I also wonder how to properly do this?
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var,Counter) ->
case Var =:= Counter of
false ->
Counter += 1,
whileloop(Var);
end.
edit:
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var, Counter) ->
case Var =:= Counter of
false ->
while_loop(Var,Counter + 1)
end.
The meaning of C += 1 is to modify the value of C. It is a non sense in Erlang since it can only give the following result:
1> C = C+1.
* 1: variable 'C' is unbound
C = 1.
1
3> C = C+1.
** exception error: no match of right hand side value 2
Keep in mind that "A = B" does not mean assigns the value of B to A, but "pattern match" A against B,
if A is unbound then it will bind to A the value of B;
if A =:= B nothing is done, the process continue;
if A =/= B then the process crashes.
So yes, if you want to have a counter, or any information that change, you must use a state variable which is passed as argument of a recursive loop. From this point of view, your last code is correct, but lets follow what happens when you call "call()" in the shell.
first it calls, in the same process - the shell - the function while_loop(10,0).
10 is not equal to 0 so it calls immediately while_loop(10,1).
10 is not equal to 1 so it calls immediately while_loop(10,2).
and so on until it calls while_loop(10,10). Now 10 =:= 10 is true, and this result does not match any clause of the case, so you get an error and the process crash.
As your code does not contain any message receive and simply loop an loop until it crashes, thhe wole process takes only a few micro seconds, so it looks like it fails immediately.
Depending on what you expect, you can imagine several types of counter, here are 2 examples:
-module(counter).
-compile(export_all).
% one counter that help you to count some events
% interface
start_c1(End) when is_integer(End) ->
spawn(?MODULE,counter1,[End]).
start_link_c1(End) when is_integer(End) ->
spawn_link(?MODULE,counter1,[End]).
inc_c1(Pid) when is_pid(Pid) ->
Ref = make_ref(),
Pid ! {inc,self(),Ref},
receive
{Ref,done} -> done;
{Ref,V} -> V
after 1000 ->
{error,no_response}
end.
value_c1(Pid) when is_pid(Pid) ->
Ref = make_ref(),
Pid ! {get_value,self(),Ref},
receive
{Ref,V} -> V
after 1000 ->
{error,no_response}
end.
stop_c1(Pid) when is_pid(Pid) ->
Pid ! stop.
% the counter
counter1(End) -> counter1_loop(End,0).
counter1_loop(End,V) ->
receive
{inc,Pid,Ref} when V =/= done ->
NewV = case V+1 of
End -> done;
Nv -> Nv
end,
Pid ! {Ref,NewV},
counter1_loop(End,NewV);
{inc,Pid,Ref} ->
Pid ! {Ref,done},
counter1_loop(End,done);
{get_value,Pid,Ref} ->
Pid ! {Ref,V},
counter1_loop(End,V);
stop ->
ok
end.
% One kind of timeout that execute something after a while -
% note it exists a similar one in the library
start_after(T,M,F,A) when is_integer(T), is_list(A) ->
Ref = make_ref(),
{Ref,spawn(?MODULE,after_receive,[T,M,F,A,self(),Ref])}.
cancel_after(P) when is_pid(P) ->
P ! cancel.
% the counter
after_receive(T,M,F,A,Pid,Ref) ->
receive
{cancel,Ref} -> Pid ! {after_receive,Ref,cancelled}
after T ->
Pid ! {after_receive,Ref,done},
apply(M,F,A)
end.
and here how to use them:
1> c("../src/counter").
{ok,counter}
2> {Ref,P} = counter:start_after(5000,io,format,["This is the end!" ]).
{#Ref<0.0.0.29>,<0.33.0>}
This is the end!3>
3> {Refa,Pa} = counter:start_after(50000,io,format,["This is the end!" ]).
{#Ref<0.0.0.34>,<0.35.0>}
4> Pa ! {cancel,Refa}.
{cancel,#Ref<0.0.0.34>}
5> flush().
Shell got {after_receive,#Ref<0.0.0.29>,done}
Shell got {after_receive,#Ref<0.0.0.34>,cancelled}
ok
6> P1 = counter:start_c1(5).
<0.52.0>
7> counter:inc_c1(P1).
1
8> counter:inc_c1(P).
{error,no_response}
9> counter:inc_c1(P1).
2
10> counter:inc_c1(P1).
3
11> counter:value_c1(P1).
3
12> counter:inc_c1(P1).
4
13> counter:inc_c1(P1).
done
14> counter:value_c1(P1).
done
15> counter:inc_c1(P1).
done
16> counter:stop_c1(P1).
stop
17> counter:inc_c1(P1).
{error,no_response}
18>
Just recursively call while_loop with the Counter argument incremented by one:
while_loop(Var, Counter + 1)
Your edited version doesn't have a clause when Var =:= Counter and thus crashes. And you'd better use pattern matching in function clauses.
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var, Var) ->
ok;
while_loop(Var, Counter) ->
while_loop(Var, Counter + 1).
And of course you'd need to do something inside the loop. You can use lambdas for that:
-module(whileloop).
-export([call/0, while_loop/3]).
call() ->
while_loop(10, 0, fun(Counter) -> io:format("Counter: ~p~n", [Counter]) end).
while_loop(Var, Var, _) ->
ok;
while_loop(Var, Counter, Fun) ->
Fun(Counter),
while_loop(Var, Counter + 1, Fun).
I am new to Erlang, I need to spawn two process running add function, then add the
two numbers.
assigned value of Process one and two is showing the process id, I need catch the value.
How can I read the return value of add(N) function in my calc function?
-module(myerl).
-export([calc/1,add/1]).
add(N) ->
N + 5.
calc(L)
pone = spawn( fun() -> add(A) end),
ptwo = spawn( fun() -> add(B) end),
Result = Pone + Ptwo,
io:format("result ~p~n", [Result]).
You need to use message passing. You must send a message back to the calling process with the result. The spawn function returns a PID (process identifier) to the newly spawned process, not the result of its execution.
This example should do what you're expecting:
calc(A, B) ->
Self = self(), % The spawned funs need a Pid to send to, use a closure
POne = spawn(fun() -> Self ! {self(), add(A)} end),
PTwo = spawn(fun() -> Self ! {self(), add(B)} end),
wait_for_response(POne, PTwo, 0).
wait_for_response(undefined, undefined, Sum) ->
Sum;
wait_for_response(POne, PTwo, Sum) ->
receive
{POne, V} -> wait_for_response(undefined, PTwo, Sum + V);
{PTwo, V} -> wait_for_response(POne, undefined, Sum + V)
end.
#Soup d'Campbells' explanation is good. I instinctively did something slightly different which, in a toy way, anticipates some bad behavior with the child processes. Also, I allow the input to be a list of numbers, not just 2.
-module(myerl).
-export([calc/1, add/1]).
calc(NumList) when is_list(NumList)->
Parent = self(),
_Pids = [spawn(fun()-> Parent ! add(ANum) end) || ANum <- NumList],
collect(length(NumList), 0);
calc(_) ->
{error, badarg}.
collect(0, Sum) ->
Sum;
collect(Cnt, Sum) ->
receive
N when is_number(N) ->
collect(Cnt-1, Sum + N);
_Bad -> % returned something that isnt a number
collect(Cnt-1, Sum)
after 1000 -> % died or is too slow
collect(Cnt-1, Sum)
end.
add(N) ->
N + 5.
-module(test_now).
-compile(export_all).
start() ->
{_, A, _} = now(),
loop(0, A).
loop(A) ->
{_, B, _} = now(),
if
B == A + 1 -> loop(0, B);
true -> loop(A)
end.
loop(T, B) ->
{_, C, _} = now(),
if
C == B + 1 -> io:write(T);
true -> loop(T+1, B)
end.
Logically this code should run 1+ second. But the result returns rapidly, far less than one second. And if I invoke test_now:start() in the Eshell frequently (up-arrow, enter,up-arrow, enter...), the results are always 999999ok.
From the documentation (now/0):
It is also guaranteed that subsequent calls to this BIF returns
continuously increasing values. Hence, the return value from now()
can be used to generate unique time-stamps, and if it is called in a
tight loop on a fast machine the time of the node can become skewed.
So you can't use now/0 to check the time like in your example. You can try os:timestamp/0 instead:
start() ->
{_, S, MS} = os:timestamp(),
loop(0, {S, MS}).
loop(T, {S, MS}=Start) ->
{_, S2, MS2} = os:timestamp(),
if
S2 == S + 1 andalso MS2 == MS -> io:format("~p~n", [T]);
true -> loop(T + 1, Start)
end.
Example:
1> timer:tc(test_timestamp, start, []).
13600591
{1000047,ok}
But if you just want to get some notification in one second consider to use erlang:send_after/3 or erlang:start_timer/3:
start() ->
erlang:send_after(1000, self(), timeout),
loop(0).
loop(T) ->
receive
timeout -> io:format("~p~n", [T])
after
0 -> loop(T + 1)
end.
Example:
1> timer:tc(test_timer, start, []).
27433087
{1000520,ok}
It's not enough to check that the seconds component of now/0 has increased if you want to wait for 1 second (i.e. C == B +1 in the if), you also have to take the microseconds component into consideration.
In the extreme case now() = {_, X, 999999}, which means that the seconds component will be X+1 in just 1 microsecond.
I have no idea why you would always get 999999 loops with this solution.
startTrains() ->
TotalDist = 100,
Trains = [trainA,trainB ],
PID = spawn(fun() ->
train(1,length(Trains)) end),
[ PID ! {self(),TrainData,TotalDist} || TrainData <- Trains],
receive
{_From, Mesg} ->
error_logger:info_msg("~n Mesg ~p ~n",[Mesg])
after 10500 ->
refresh
end.
so, I created Two Processes named trainA, trainB. I want to increment these process by 5 till it gets 100. I made different processes to make each of the train (process) increments its position parallely. But I was surprised to get the output sequentially i.e process trainA ends then process trainB starts. But I want to increment themselves at simultaneously.
I want to run processes like this
trainA 10 trainB 0
trainA 15 trainB 5
....
trainA 100 trainB 100
but I m getting
trainA 0
....
trainA 90
trainA 95
trainA 100
trainA ends
trainB 0
trainB 5
trainB 10
.....
trainB 100
How to make the processes run parallel/simultaneously? Hope you get my Q's. Please help me.
You spawn only one process initialized by function train/2. Your presented code is incomplete so I can only guess but I think your code is wrong because you have only one train process. For inspiration:
-module(trains).
-export([startTrains/0]).
startTrains() ->
TotalDist = 100,
Names = [trainA,trainB ],
Self = self(),
Trains = [spawn_link(fun() ->
train(Name, Self) end) || Name <- Names],
[ Train ! {start, Self, 0, TotalDist} || Train <- Trains],
ok = collectResults(Names).
collectResults([]) -> ok;
collectResults(Trains) ->
receive
{stop, Name, Pos, Length} ->
io:format("~p stops at ~p (~p)~n", [Name, Pos, Length]),
collectResults(Trains -- [Name]);
Msg ->
io:format("Supervisor received unexpected message ~p~n", [Msg]),
collectResults(Trains)
after 10500 -> timeout
end.
train(Name, Sup) ->
receive
{start, Sup, Pos, Length} -> run_train(Name, Sup, Pos, Length);
Msg ->
io:format("~p received unexpected message ~p~n", [Name, Msg]),
train(Name, Sup)
end.
run_train(Name, Sup, Pos, Length)
when Pos < Length ->
receive after 500 ->
NewPos = Pos + 5,
io:format("~p ~p~n", [Name, Pos]),
run_train(Name, Sup, NewPos, Length)
end;
run_train(Name, Sup, Pos, Length) ->
Sup ! {stop, Name, Pos, Length}.
But if I would think it seriously I should look to gen_fsm and OTP principles. But in your current stage keep play with erlang primitives to take better feeling first.