1

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

在外壳中,我尝试输入:

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),[]).但出现错误。

4

2 回答 2

4

正如@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().

这里是如何测试它(在一个新的外壳,所以你不必使用 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
于 2013-03-13T09:10:59.560 回答
1

如果您在文件中定义了函数接收/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.
于 2013-03-13T05:47:24.890 回答