【问题标题】:If..else if statement within receive..end statement?if..else if 语句在 receive..end 语句中?
【发布时间】:2014-06-26 02:34:20
【问题描述】:

我正在尝试在 receive..end. 语句中的 Erlang 中创建 if..else if 条件,以便传递两个变量 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),[]).,但出现错误。

【问题讨论】:

  • 你得到的错误意味着shell中的变量Pid已经被绑定了。您生成了一个新进程,因此您得到了一个与 Pid 不匹配的新 pid。请记住,shell 变量也是不可变的。

标签: if-statement process erlang


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    如果你在你的文件中定义了一个函数 received/2,这意味着你有类似的东西:

    -module(ifelse).
    -export([receiving/0,receiving/2]).
    
    receiving() ->
        some_code.
    
    receiving(A,B) ->
        other_code.
    

    你可以用

    来调用它

    Pid = spawn(ifelse,receiving,[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.
    

    【讨论】:

      猜你喜欢
      • 2019-04-09
      • 1970-01-01
      • 2017-02-05
      • 1970-01-01
      • 2015-07-06
      • 2012-08-05
      • 2021-09-11
      • 1970-01-01
      相关资源
      最近更新 更多