if..else if receive..end语句中的语句?

时间:2013-03-12 23:18:22

标签: if-statement process erlang

我正在尝试在if..else if语句中在Erlang中创建receive..end.条件,以便传递两个变量A和B,以便可以测试它们的等效性。

在shell中我尝试输入:

6> Pid = spawn(ifelse,receiving,[]).
** exception error: no match of right hand side value <0.54.0>
7> 

我想要的是使用Pid ! {self(), 1,2}.Pid ! {self(), 2,2}.来测试这两种情况,但是出了点问题。

-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.

顺便说一句,如果我有receiving(A,B)代替两个变量,我将如何与Pid = spawn(ifelse,receiving,[]).类似地生成?我尝试使用Pid = spawn(ifelse,receiving(1,2),[]).但是出错了。

2 个答案:

答案 0 :(得分:4)

正如@rvirding评论的那样,Erlang是单一的分配。您的问题可能与您已将值绑定到变量Pid的事实有关,因此您无法将任何新值绑定到它。

只有在shell中(不推荐在实际代码中)才能使用f(变量)取消绑定单个变量:

1> A = 4.
4
2> f(A).
ok
3> A = 5.
5

或使用f()取消绑定所有变量 请注意,这仅用于测试目的。

据我所知,您的代码是正确的,即使我建议您使用case和模式匹配而不是if语句。

所以我会按如下方式重写你的代码:

-module(ifelse).
-export([receiving/0]).

receiving() ->
    receive
        {Pid, A, B} ->
            case A =:= B of
                true ->
                    Pid ! "True";
                false ->
                    Pid ! "False"
            end
     end.

您可以按如下方式测试:

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"

另一件事是我不明白为什么你应该使用字符串值“True”和“False”,因为你实际上可以使用原子。此外,您的代码只能运行一次,因为在if-else或case之后,进程就会死掉。您可以使用递归函数来解决此问题。

这是一个包含两个修改的模块:

-module(ifelse).
-export([receiving/0]).

receiving() ->
    receive
        {Pid, A, B} ->
            Pid ! A =:= B
    end,
receiving().

以下是如何测试它(在一个新的shell中,所以你不必使用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

答案 1 :(得分:1)

如果您在文件中定义了一个接收/ 2的函数,则表示您有类似的内容:

-module(ifelse).
-export([receiving/0,receiving/2]).

receiving() ->
    some_code.

receiving(A,B) ->
    other_code.

你可以用

来打电话
  

Pid = spawn(ifelse,receive,[1,2])。

顺便说一句,在erlang中编写if语句并不常见,原因是如果一个case与任何条件都不匹配,代码就会崩溃。

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> 

如果你想避免这种情况,你必须有一个默认的警卫(然后它看起来像一个案例)。

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> 

编写函数的常用方法更像是:

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.

我在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.
相关问题