Returning value from if else in ERLANG - erlang

parse(Tuples,Str,Block) ->
if Block =:= 1 ->
Str1=string:substr(Str,1,1),
Str2=string:substr(Str,2,4),
Tuple2=Tuples++[{a,Str1},{b,Str2}];
Block =:= 2 ->
Str3=string:substr(Str,1,1),
Str4=string:substr(Str,2,3),
Tuple2=Tuples++[{c,Str3},{d,Str4};
true-> ok
end.
I am a newbie to erlang. Is there a way to return the tuple2 value from this function? if not what is the work around?
when i try to return Tuple2 after end it gives
variable 'Tuple2' unsafe in 'if'.
and when i use it above 'if' the Tuple2 cannot be altered.

In your code, Tuple is being 'returned' in the first two cases. Remember, in Erlang the last expression is always used as the return value. The reason you get the warning is that Tuple2 is not given a value in all branches. For example, what if Block was 3? Tuple2 would not be defined.
Let's rewrite this in a more idiomatic way to better see what is returned:
parse(Tuples,Str,Block) ->
case Block of
1 ->
Str1=string:substr(Str,1,1),
Str2=string:substr(Str,2,4),
Tuple2=Tuples++[{a,Str1},{b,Str2}];
2 ->
Str3=string:substr(Str,1,1),
Str4=string:substr(Str,2,3),
Tuple2=Tuples++[{c,Str3},{d,Str4};
_ ->
ok
end.
The last expression in each branch of the case expression will be 'returned'.
If you don't see this, consider the following:
1> case 1 of
1> 1 -> ok;
1> 2 -> nok
1> end.
ok
ok is 'returned' from that case expresion (the case expression evaluates to ok).
Let's rewrite the original code to be even more idiomatic:
parse(Tuples, Str, 1) ->
Str1=string:substr(Str,1,1),
Str2=string:substr(Str,2,4),
Tuple2=Tuples++[{a,Str1},{b,Str2}];
parse(Tuples, Str, 2) ->
Str3=string:substr(Str,1,1),
Str4=string:substr(Str,2,3),
Tuple2=Tuples++[{c,Str3},{d,Str4};
parse(_, _, _) ->
ok.

Related

Calling functions within case pattern matching is illegal pattern?

-module(erltoy).
-compile(export_all).
isFive(5) -> true;
isFive(_) -> false.
foo(X) ->
case X of
isFive(X) -> true;
3 -> false;
_ -> nope
end.
1> c(erltoy).
erltoy.erl:9: illegal pattern
error
Can I not call functions as part of the pattern match?
isFive(X) -> true; contains expression's which can't be computed to a constant at compile time and thus is not a valid pattern as a result. An arithmetic expression can be used within a pattern if it meets both of the following two conditions:
It uses only numeric or bitwise operators.
Its value can be evaluated to a constant when complied.
See this Example from the Erlang reference manual
case {Value, Result} of
{?THRESHOLD+1, ok} -> ...
to complete #byaruhaf answer, the left part of a case clause doesn't need to be a constant when compiled. the following code is valid, and obviously, Temp is not known at compile time (but foo(5) evaluates to nope!).
-module(erltoy).
-compile(export_all).
isFive(5) -> true;
isFive(_) -> false.
foo(X) ->
Temp = isFive(X),
case X of
Temp -> true;
3 -> false;
_ -> nope
end.
It is even not necessary that the left part is bound at execution time, for example, this is also valid, and there I is unbound before the case evaluation, and bound during the pattern matching:
get_second_element_of_3_terms_tuple_if_pos_integer(X) ->
case X of
{_,I,_} when is_integer(I), I>0 -> {true,I};
_ -> false
end.
The left part of a case must be a valid pattern with an optional guard sequence.
A valid pattern is an erlang term that may contains unbound variables, it may also contain arithmetic expressions if they respect the 2 conditions
It uses only numeric or bitwise operators.
Its value can be evaluated to a constant when complied.
the definition of a guard sequence is given there in erlang documentation
A final remark, the usual erlang way to code the kind of test function given in your example is to use different function heads, just as you do for isFive/1 definition.

Our own tuple_to_list() function

I'm required to write my own tuple_to_list() function (yes, from the book) and came up with this in my erl file:
%% Our very own tuple_to_list function! %%
% First, the accumulator function
my_tuple_to_list_acc(T, L) -> [element(1, T) | L];
my_tuple_to_list_acc({}, L) -> L;
% Finally, the public face of the function
my_tuple_to_list(T) -> my_tuple_to_list_acc(T, []).
When I compile this, however, I get the following error in the shell:
28> c(lib_misc).
lib_misc.erl:34: head mismatch
lib_misc.erl:2: function my_tuple_to_list/1 undefined
error
I have no clue what "head mismatch" there is, and why is the function undefined (I've added it to the module export statement, though I doubt this has much to do with export statements)?
The other answer explains how to fix this, but not the reason. So: ; after a function definition clause means the next clause continues the definition, just like as for case and if branches. head mismatch means you have function clauses with different names and/or number of arguments in one definition. For the same reason, it is an error to have a clause ending with . followed by another clause with the same name and argument count.
Changing the order of the clauses is needed for a different reason, not because of the error. Clauses are always checked in order (again, same as for case and if) and your first clause already matches any two arguments. So the second would never be used.
Those errors mean that you didn't end definition of my_tuple_to_list_acc/2.
You should change order of first two code lines and add dot after them.
my_tuple_to_list_acc({}, L) -> L;
my_tuple_to_list_acc(T, L) -> [element(1, T) | L].
When you are interested in working tuple_to_list/1 implementation
1> T2L = fun (T) -> (fun F(_, 0, Acc) -> Acc; F(T, N, Acc) -> F(T, N-1, [element(N, T)|Acc]) end)(T, tuple_size(T), []) end.
#Fun<erl_eval.6.50752066>
2> T2L({}).
[]
3> T2L({a,b,c}).
[a,b,c]
Or in module
my_typle_to_list(_, 0, Acc) -> Acc;
my_typle_to_list(T, N, Acc) ->
my_typle_to_list(T, N-1, [element(N, T)|Acc]).
my_typle_to_list(T) ->
my_typle_to_list(T, tuple_size(T), []).
Note how I use decreasing index for tail recursive function.

Erlang, Matching with list foreach

I've been making a chat application in Erlang for a school project, but I've run into an issue. I'm trying to make my program concurrent and in order to do so I start a new thread for each message a channel is sending. I do this using lists:foreach, but I want to make sure that I don't message the person who typed in the channel.
request(State, {message, {UserID,UserPID}, Token}) ->
case catch lists:member({UserID,UserPID}, State#channel.users) of
false ->
{{error, user_not_joined}, State};
true ->
spawn( fun() ->
ListOfUsers = State#channel.users,
UserPIDs = lists:map(fun ({_, V}) -> V end, ListOfUsers),
%spawn( fun() ->end)
lists:foreach(
fun(UserPID) -> ok end,
fun(PID) ->
spawn( fun() -> genserver:request(PID, {message_from_server, State#channel.name, UserID, Token}) end)
end, UserPIDs) end),
{ok, State}
end;
What I pretty much want to do is to match with the UserPID inside the foreach. As of now I only get warnings:
channel.erl:39: Warning: variable 'UserPID' is unused
channel.erl:39: Warning: variable 'UserPID' shadowed in 'fun'
Line 3 is fun(UserPID) -> ok end,
Cheers
The answer by legoscia is fine, but I'd add that often list comprehension is simpler to use and simpler to read than lists:foreach. Note that list comprehension is able to ignore values based on clauses. Consider the following example:
-module(filter).
-export([do/0]).
do() ->
Values = lists:seq(1,10),
IgnoreThisValue = 5,
%% print all values unequal to IgnoreThisValue
[io:format("Value: ~b~n", [Value]) ||
Value <- Values, Value =/= IgnoreThisValue],
ok.
Run it in the shell:
1> make:all([load]).
Recompile: filter
up_to_date
2> filter:do().
Value: 1
Value: 2
Value: 3
Value: 4
Value: 6
Value: 7
Value: 8
Value: 9
Value: 10
A side note on your code: Why do you spawn a thread per process? I assume that you are using the behaviour gen_server (correct me if I am wrong). If so, you should consider using the cast function to simply send a message. As you do not check the result of genserver:request/2, this might be a viable option which saves you a lot of processes.
Since the function argument shadows the existing variable, you need to use a guard for that:
fun(PID) when PID =:= UserPID -> ok end

Counting down from N to 1

I'm trying to create a list and print it out, counting down from N to 1. This is my attempt:
%% Create a list counting down from N to 1 %%
-module(list).
-export([create_list/1]).
create_list(N) when length(N)<hd(N) ->
lists:append([N],lists:last([N])-1),
create_list(lists:last([N])-1);
create_list(N) ->
N.
This works when N is 1, but otherwise I get this error:
172> list:create_list([2]).
** exception error: an error occurred when evaluating an arithmetic expression
in function list:create_list/1 (list.erl, line 6)
Any help would be appreciated.
You should generally avoid using append or ++, which is the same thing, when building lists. They both add elements to the end of a list which entails making a copy of the list every time. Sometimes it is practical but it is always faster to work at the front of the list.
It is a bit unclear in which order you wanted the list so here are two alternatives:
create_up(N) when N>=1 -> create_up(1, N). %Create the list
create_up(N, N) -> [N];
create_up(I, N) ->
[I|create_up(I+1, N)].
create_down(N) when N>1 -> %Add guard test for safety
[N|create_down(N-1)];
create_down(1) -> [1].
Neither of these are tail-recursive. While tail-recursion is nice it doesn't always give as much as you would think, especially when you need to call a reverse to get the list in the right order. See Erlang myths for more information.
The error is lists:last([N])-1. Since N is an array as your input, lists:last([N]) will return N itself. Not a number you expect. And if you see the warning when compiling your code, there is another bug: lists:append will not append the element into N itself, but in the return value. In functional programming, the value of a variable cannot be changed.
Here's my implementation:
create_list(N) ->
create_list_iter(N, []).
create_list_iter(N, Acc) ->
case N > 0 of
true -> NewAcc = lists:append(Acc, [N]),
create_list_iter(N-1, NewAcc);
false -> Acc
end.
If I correctly understand your question, here is what you'll need
create_list(N) when N > 0 ->
create_list(N, []).
create_list(1, Acc) ->
lists:reverse([1 | Acc]);
create_list(N, Acc) ->
create_list(N - 1, [N | Acc]).
If you work with lists, I'd suggest you to use tail recursion and lists construction syntax.
Also, to simplify your code - try to use pattern matching in function declarations, instead of case expressions
P.S.
The other, perhaps, most simple solution is:
create_list(N) when N > 0 ->
lists:reverse(lists:seq(1,N)).

Erlang - case construction

I'm new to Erlang and I've tried some Erlang constructions.
My program should behave something like that:
if x == 42:
print "Hi"
else:
print "Hello"
Here is my code in Erlang
-module(tested).
-export([main/0]).
main() ->
{ok, X} = io:fread("","~d"),
case X == 42 of
true -> io:fwrite("Hi\n");
false -> io:fwrite("Hello\n")
end.
Thanks in advance for help.
Use {ok, [X]} = io:fread("","~d") (brackets around X).
fread returns a list as the second element of the tuple (which makes sense in case you're reading more than one token), so you need to get the element out of the list before you can compare it to 42.
Note that instead of pattern matching on the result of ==, you could simply pattern match on X itself, i.e.:
case X of
42 -> io:fwrite("Hi\n");
_ -> io:fwrite("Hello\n")
end.

Resources