If..else if statement within receive..end statement? - if-statement

I'm trying to create an if..else if condition in Erlang within a receive..end. statement in order to pass two variables A and B so that they can be tested for equivalence.
In the shell I tried typing:
6> Pid = spawn(ifelse,receiving,[]).
** exception error: no match of right hand side value <0.54.0>
7>
What I wanted was to use Pid ! {self(), 1,2}. and Pid ! {self(), 2,2}. to test both cases but something is wrong.
-module(ifelse).
-export([receiving/0]).
receiving() ->
receive
{Pid,A,B}->
if
A =:= B ->
io:format(" B equals A ~n"),
Pid ! "True";
A =/= B ->
io:format(" B does not equal A ~n"),
Pid ! "False";
true -> {error, wrong_value}
end
end.
By the way if I have receiving(A,B) instead with two variables how would I spawn that similarly to Pid = spawn(ifelse,receiving,[]).? I tried using Pid = spawn(ifelse,receiving(1,2),[]). but that gave an error.

As #rvirding commented, Erlang is single assignement. Your problem is probably related to the fact that you have already bound a value to variable Pid and therefore you can't bind any new value to it.
Only in a shell (not recommended in real code) can you unbind a single variable using f(Variable):
1> A = 4.
4
2> f(A).
ok
3> A = 5.
5
or unbind all the variables using f()
Notice that this is only for testing purposes.
As far as I can see your code is right, even though I suggest you to use case and pattern matching instead of an if statement.
So I would rewrite your code as follows:
-module(ifelse).
-export([receiving/0]).
receiving() ->
receive
{Pid, A, B} ->
case A =:= B of
true ->
Pid ! "True";
false ->
Pid ! "False"
end
end.
You can test it as follows:
1> Pid = spawn(ifelse,receiving,[]).
<0.34.0>
2> ShellPid = self().
<0.32.0>
3> Pid ! {ShellPid, 4, 5}.
{0.32.0, 4, 5}
4> flush().
Shell got "False"
Another thing is that I don't see why you should use a string value for "True" and "False" since you could actually use atoms. Moreover your code can work only once because after the if-else or case the process just dies. You can tackle this issue by using a recursive function.
Here is a module with both the modifications:
-module(ifelse).
-export([receiving/0]).
receiving() ->
receive
{Pid, A, B} ->
Pid ! A =:= B
end,
receiving().
and here is how to test it (in a new shell so you don't have to use f() ):
1> Pid = spawn(ifelse,receiving,[]).
<0.34.0>
2> ShellPid = self().
<0.32.0>
3> Pid ! {ShellPid, 4, 5}.
{0.32.0, 4, 5}
4> flush().
Shell got false
5> Pid ! {ShellPid, 4, 4}.
{0.32.0, 4, 4}
6> flush().
Shell got true

If you have define a function receiving/2 in your file, that means you have something like :
-module(ifelse).
-export([receiving/0,receiving/2]).
receiving() ->
some_code.
receiving(A,B) ->
other_code.
you may call it with
Pid = spawn(ifelse,receiving,[1,2]).
By the way, it is not usual to write if statements in erlang, The reason is that if one case doesn't match any condition, the code will crash.
5> F=fun(X) -> if (X rem 2) == 0 -> X+1 end end.
#Fun<erl_eval.6.82930912>
6> F(4).
5
7> F(5).
** exception error: no true branch found when evaluating an if expression
8>
If you want to avoid this, you have to have a default guard (and then it looks like a case).
8> F1=fun(X) -> if (X rem 2) == 0 -> X+1;
8> true -> X end end.
#Fun<erl_eval.6.82930912>
9> F1(4).
5
10> F1(5).
11>
The usual way to code your function is more like this:
receiving() ->
receive
{Pid,_A,_A} when is_pid(Pid) ->
% use the pattern matching to verify that the 2 elements are equal
% and a guard test to check that the first element is a pid.
% Note that in this case it is a strict equals. I use _A because the code doesn't
% care of the value itself
io:format(" B equals A ~n"),
Pid ! "True";
{Pid,_,_} when is_pid(Pid) ->
% use pattern maching to verify the that message is a tupple of 3 elements
% and a guard test to check that the first element is a pid.
% For the 2 last elements I use _, so the data is not bound to any variable,
% only the structure is tested
io:format(" B does not equal A ~n"),
Pid ! "False";
_ -> {error, wrong_value}
end.
I tested this in the shell:
14> F = fun() ->
14> receive
14> {Pid,_A,_A} when is_pid(Pid) ->
14> io:format(" B equals A ~n"),
14> Pid ! "True";
14> {Pid,_,_} when is_pid(Pid) ->
14> io:format(" B does not equal A ~n"),
14> Pid ! "False";
14> _ -> {error, wrong_value}
14> end
14> end.
#Fun<erl_eval.20.82930912>
15> Pid = spawn(F).
<0.58.0>
16> Pid ! {self(),1,2}.
B does not equal A
{<0.51.0>,1,2}
17> % the returm value of "proc ! Mess" is Mess. It is what we get on the console on previous line
17> flush(). % use flush() to get the messages received by the shell
Shell got "False"
ok
18> Pid ! {self(),test,test}. % the process Pid is terminated now. when we send a message to it,
18> % it is simply "lost".
{<0.51.0>,test,test}
19> % it is necessary though to use a new variable Pid1 and spawn a new process
19> % (see rvirding message and user601836 answer)
19> Pid1 = spawn(F).
<0.63.0>
20> Pid1 ! {self(),test,test}.
B equals A
{<0.51.0>,test,test}
21> flush().
Shell got "True"
ok
22> Pid2 = spawn(F).
<0.68.0>
23> Pid2 ! {hello,test,test}.
{hello,test,test}
24> flush().
ok
25> % of course there is no message sent back, no io:format to print something on the console,
25> % the returned value of the function in the error case is "lost".
25> % if you want to have a permanent process you must have a recursive loop,
25> % calling receiving() were needed.

Related

Concurrency in Erlang

The problem I am trying to solve is as follows:
Write an Erlang function named squared that takes no parameters. This function should wait to receive a message. The message will be in the format { Pid, N }, where you may assume that Pid is a process ID and N is a number. The function should send a message to the process ID Pid in the form { Me, X } where Me is the process ID of the process running the function and X is the value of N squared. The function should then end.
so far I have this:
-module(main).
-export([squared/0]).
squared() ->
receive
{Pid,N} -> Pid ! {Me, X}, squared();
terminate -> ok
end.
The error that I am getting is as follows:
3> c(main).
main.erl:7: variable 'Me' is unbound
main.erl:7: variable 'X' is unbound
main.erl:7: Warning: variable 'N' is unused
error
I am also having trouble in the second part of the problem where it is asking us to send a message to the process ID in the form {Me, X}. Where Me is the process ID and X is the value of N squared. How will we do that?
for implement your function you can write a function like bellow
-module(main).
-export([squared/0]).
squared() ->
receive
{Pid,N} ->
Pid ! {self(), N*N},
squared();
terminate ->
ok
end.
Me should be the pid of the receiving process, i.e. self(). N squared is just N*N.
-module(main).
-export([squared/0]).
squared() ->
receive
{Pid, N} ->
Pid ! {self(), N*N};
terminate -> ok
end.
Or, if you want to be more verbous:
squared() ->
Me = self(),
receive
{Pid, N} ->
X = N * N,
Pid ! {Me, X};
terminate -> ok
end.

Erlang concurrent programming

Write an Erlang function named calculator that takes no arguments. The function, when run in a process, should wait to receive a message. If the message is in the form of a tuple of four items: { Pid, Operand, X, Y }, do this:
If Operand is add, send a message to Pid with the result of adding X and Y.
If Operand is subtract, send a message to Pid with the result of subtracting Y from X.
If Operand is multiply, send a message to Pid with the result of multiplying X and Y.
If Operand is divide, send a message to Pid with the result of dividing X by Y.
Then, rerun the function.
If the message is in the form of a tuple with two items: { Pid, terminate }, then send a message to Pid of done. Do not rerun the function.
If the message is of any other form, ignore it and rerun the function.
My code:
calculate() ->
receive
{Pid, Operand, X, Y}
if
Operand == "add" -> Pid ! X+Y
Operand == "substract" -> Pid ! Y - X
Operand == "multiply" -> Pid ! X*Y
Operand == "divide" -> Pid ! X/Y
{Pid, terminate} -> Pid ! "done"
_ -> calculate();
end.
Can someone help me with this problem?
Your code does not compile, you should have a look at the basic erlang syntax first.
I give you some clues:
you should not use the if statement for your problem but use pattern matching instead like in
receive
{From,add,X,Y} ->
From ! X+Y,
calculate();
{From,sub,X,Y} ->
...
Generally, for this purpose, use atoms like add rather than string like "add"
you should have a function to start the function calculate/0 in a separate process:
start() ->
spawn(fun() -> calculate() end).

How do I restart an erlang process in a list?

I have a list construction like this:
[{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List]
So I have a list with values and each value is handed in its own process with the line above. If one worker dies, I want to restart it (with the same value). I have saved the Value in the same tupel as the new process as above. Can I do some list comprehension to determine if the process has died, and in that case, start a new?
Use erlang:monitor/2 to watch for your processes:
List1 = [{Value, spawn_link(fun() -> worker(Value, self()) end)} || Value <- List],
List2 = [{Value, Pid, monitor(process, Pid)} || {Value, Pid} <- List1]
And then wait for messages for monitors, restart your processes if you need and update List2 with new pids and monitors.
To get more info about erlang:monitor/2 read appropriate man page.
In your home made supervisor, don't forget to set process_flag(trap_exit, true) otherwise it will die at the same time one child die, and then all other children too:
1> F = fun() -> timer:sleep(2000) end.
#Fun<erl_eval.20.80484245>
2> F1 = fun() -> timer:sleep(2000), 1/0 end.
#Fun<erl_eval.20.80484245>
3> S = fun() -> spawn_link(F), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
4> S1 = fun() -> spawn_link(F1), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
5> S1b = fun() -> process_flag(trap_exit, true), spawn_link(F1), receive M-> M after 5000 -> no_message end end.
#Fun<erl_eval.20.80484245>
6> self().
<0.40.0>
7> S().
no_message
8> self().
<0.40.0>
9> S1().
=ERROR REPORT==== 15-Mar-2014::06:46:27 ===
Error in process <0.49.0> with exit value: {badarith,[{erlang,'/',[1,0],[]}]}
** exception exit: badarith
in operator '/'/2
called as 1 / 0
10> self().
<0.50.0>
11> S1b().
=ERROR REPORT==== 15-Mar-2014::06:46:39 ===
Error in process <0.53.0> with exit value: {badarith,[{erlang,'/',[1,0],[]}]}
{'EXIT',<0.53.0>,{badarith,[{erlang,'/',[1,0],[]}]}}
12> self().
<0.50.0>
13>
Unless you are doing this for education purpose, I recommend you to use the erlang otp supervisors, with a one_for_one restart strategy.
First, create a function that creates a process that monitors a Pid and executes a Fun when it dies, like so:
on_exit(Pid, Fun) ->
spawn(fun() ->
Ref = monitor(process, Pid),
receive
{'DOWN', Ref, process, Pid, Why} ->
Fun(Why)
end
end).
Now, you can use the on_exit function to create a function for creating processeses that will restart automatically when the process dies:
keep_alive(Fun) ->
process_flag(trap_exit, true),
Pid = spawn_link(Fun),
on_exit(Pid, fun(Why) ->
io:format("Process died: ~p, restarting it~n", [Why]),
keep_alive(Fun) end),
Pid.
With these little two functions, your work to create processes that will restart automatically is reduced to simply calling keep_alive in your list comprehension:
[{Value, keep_alive(fun() -> worker(Value, self()) end)} || Value <- List].
P.S.: These two little functions are presented almost exactly like this in chapter 13 of the book Programming Erlang 2nd Edition, I only did some minor changes to better suit to your case.

Error: Instance : Num (a -> b) when I try to get the sign of the elements of a list

This is what I want to do:
INPUT: [1,2,3,-1,-2,-3]
OUTPUT:[1,1,1,-1,-1,-1]
I tried this:
signNum (x:n) = map(if x>0
then 1
else -1)n
Can anyone tell me where I've made a mistake in the logic?
The first problem is that map expects a function. So you have to wrap your if statement in a lambda. However, this will still not do exactly what you want. Instead of breaking the list into its head and tail, your really want to map your function over the whole list.
Remember that map just takes a function and applies it to each element. Since you want to turn each element into either 1 or -1, you just need to map the appropriate function over your list.
So in the end, you get:
sigNum ls = map (\ x -> if x > 0 then 1 else - 1) ls
In this case, it is probably easier to break the function down into smaller parts.
At the very lowest level, one can compute the signum of a single number, i.e.:
signum :: (Num a, Ord a) => a -> a
signum x = if x > 0 then 1 else -1
Once you have this, you can then use it on a list of numbers, like you would for any function:
signNum ls = map signum ls
(p.s. what is signum 0 meant to be? Your current definition has signum 0 = -1.
If you need to expand the function to include this case, it might be better to use guards:
signum x | x < 0 = -1
| x == 0 = 0
| otherwise = 1
or a case statement:
signum x = case compare x 0 of
LT -> -1
EQ -> 0
GT -> 1
)
Your comments suggest you'd like to be able to do this with a comprehension.
How to use a comprehension
If you do want to do this with a comprehension, you can do
signNum ls = [ if x>0 then 1 else -1| x <- ls ]
How not to use a comprehension
...but you can't put the condition on the right hand side
brokenSignNum ls = [ 1| x <- ls, x > 0 ]
Because putting a condition on the right hand side removes anything that
doesn't satisfy the condition - all your negatives get ignored! This would
shorten your list rather than replace the elements. Let's try
brokenSignNum2 ls = [ 1| x <- ls, x > 0 ] ++ [ -1| x <- ls, x <= 0 ]
This has the same length as your original list but all the positives are at the front.
Summary: you have to put this conditional expression on the left hand side
becuase that's the only place substitution can happen - on the right hand side it does deletion.
Is zero negative?
Note that your if statement counts 0 as negative. Are you sure you want that? Perhaps you'd be better with defining the sign of a number seperately:
sign x | x == 0 = 0 -- if x is zero, use zero
| x > 0 = 1 -- use 1 for positives
| x < 0 = -1 -- use -1 for negatives
workingSignNum1 ls = [sign x | x <- ls]
But sign is (almost) the same as the function signum, so we may as well use that
workingSignNum2 ls = [signum x | x <- ls]
Making it tidier
Now that's a lot of syntax for what basically means "replace x with sign x all along the list ls". We do that kind of thing a lot, so we could write a function to do it:
replaceUsing :: (a -> b) -> [a] -> [b]
replaceUsing f xs = [f x | x <- xs]
but there's already a function that does that! It's called map. So we can use map on our list:
quiteSlickSignNum :: Num a => [a] -> [a]
quiteSlickSignNum ls = map signum ls
or even slicker:
slickSignNum :: Num a => [a] -> [a]
slickSignNum = map signum
which is how I would have defined it.
Why did you say sign was almost the same as signum?
sign takes a number and returns a number, 1, 0, or -1, but what's the type of 1?
Well, 1 has the type Num a => a so you can use it with any numeric type. This means
sign takes any type of number and returns any type of number, so its type is
sign :: (Num a,Num b) => a -> b
so my version of sign can give you a different type. If you try it out, you'll find that 3 * sign 4.5 gives you 3, not 3.0, so you can get an Integer out of it, but also if you do 3.14 * sign 7.4, you get 3.14, so you can get a decimal type too. By contrast,
signum :: Num a => a -> a
so it can only give you back the type you gave it - 3 * signum 4.5 gives you 3.0.
The error message "no instance for Num" is one of the trickiest for new Haskellers to decipher. First, here's the fully polymorphic type signature for the function you are trying to write (I added this to the source file in order to get the same error as you):
signNum :: (Ord a, Num a) => [a] -> [a]
Finding the error
Now, the compile error message says:
Could not deduce (Num (a -> a)) from the context (Ord a, Num a)
arising from the literal `1' at prog.hs:3:17
Notice that the error message gives us the location of the problem. It says that "the literal 1" at file_name.hs:line_number:column_number is the problem.
signNum (x:n) = map(if x>0
then 1 -- <-- here's the problem! (according to that message)
else -1)n
Understanding the error
Now, the error message also suggests some possible fixes, but whenever you run into "no instance for Num", the suggested "possible fixes" are almost always wrong, so ignore them. (I wish GHC would provide better error messages for Num-related stuff like this).
Recall what the error message said:
Could not deduce (Num (a -> a)) ... arising from the literal `1' ...
What this means is that you put a literal 1 somewhere where the context expected something of type
a -> a. 1 is obviously not a function, so either the context is wrong, or the number 1 is wrong.
So what is the context of the literal 1?
Finding the error (precisely)
(if x > 0
then <<hole>>
else -1)
If statements in Haskell produce a value. The branches of an if statement must have the same type, and the type of the if statement is determined by the type of the branches.
Here, the other branch has the value -1, which is a number. So we therefore expect the <<hole>> to have the same type: a number. Well, this obviously isn't the problem (since 1 is a number), so let's look at the context of that expression.
map <<hole>> n
The map function expects a function as its first argument. However, we know the <<hole>> will produce a number. Eureka! Here's the discrepancy: we're giving map a number where it expects a function.
Correcting the error
The obvious solution -- now that we know precisely what and where the problem is -- is to give map a function, rather than a number. See the various other answers for details.

Binary to list strange output

I have following code:
file:write(FileId, Packet),
file:close(FileId),
{ok, FileId1} = file:open("tmp/" ++ integer_to_list(Summ), [read]),
A = file:read_file("tmp/" ++ integer_to_list(Summ)),
{_, B} = A,
io:format(binary_to_list(B));
In the end of function i see io:format B output. But if i make that:
file:write(FileId, Packet),
file:close(FileId),
{ok, FileId1} = file:open("tmp/" ++ integer_to_list(Summ), [read]),
A = file:read_file("tmp/" ++ integer_to_list(Summ)),
{_, B} = A,
S = binary_to_list(B),
io:format(S);
io:format nothing output. Why?
Thank you.
You should probably not rely on the single-argument io:format/1 function:
3> B="helo\n".
"helo\n"
4> io:format(B).
helo
ok
5> C="~p".
"~p"
6> io:format(C).
** exception exit: {badarg,[{io,format,[<0.26.0>,"~p",[]]},
{erl_eval,do_apply,5},
{shell,exprs,6},
{shell,eval_exprs,6},
{shell,eval_loop,3}]}
in function io:o_request/3
If the argument contains any formatting requests, your io:format call may die. I would recommend using a format string such as ~p~n or ~w~n:
1> C="~p".
"~p"
2> io:format("~p~n", [C]).
"~p"
ok
It does work perfectly well here:
3> {ok, FileId1} = file:open("tmp/" ++ integer_to_list(Summ), [read]),
3> A = file:read_file("tmp/" ++ integer_to_list(Summ)),
3> {_, B} = A,
3> S = binary_to_list(B),
3> io:format(S).
1213
The argument to io:format/1 is a format string which must not include any formatting control sequences which require arguments. If this occurs an error is generated. To output raw printable characters use io:put_chars/1.