2014-11-02 89 views
2

基本上我有一个包含Value和Id列表的结构。 我想要做的是映射到Ids列表并发送消息给他们,但是当我第一次初始化Ids列表时,我把变量“empty_set”(也许我应该重命名为empty_list:P)。如何检查Erlang中的列表是否为空?

问题是,无论何时我调用地图函数,我想首先检查列表是否为“empty_set”,如果不是,则使用地图函数。下面是代码:

{From, set_value, V} -> 
    if ViewerSet /= empty_set -> set_viewer_values(V, ViewerSet) 
    end, 
looper(V, ViewerSet) 

这是调用的函数:

set_viewer_values(Value, ViewerSet) -> 
    if ViewerSet /= empty_set -> 
    lists:map(fun(ViewerPid) -> 
     ViewerPid ! {self(), set_value, Value} end, ViewerSet) 
    end. 

这是我如何启动这一过程:

process() -> 
    C = spawn(fun() -> looper(no_value, empty_set) end), 
    {ok, C}. 

的问题是,当我运行它我收到此错误:

=ERROR REPORT==== 2-Nov-2014::15:03:07 === 
Error in process <0.367.0> with exit value: {function_clause,[{lists,map, 
[#Fun<sheet.2.12938396>,empty_set],[{file,"lists.erl"},{line,1223}]},{lists,map,2, 
[{file,"lists.erl"},{line,1224}]},{sheet,cell_loop,2,[{file,"sheet.erl"},{line,93}]}]} 

根据我的理解,尽管if表达式必须检查列表是否为空,它仍会尝试映射它。

那么我在做什么错误的表达?

谢谢

回答

2

模式匹配。如果您需要检查警卫中的空列表或ifcond,那么您几乎可以确定您在思考Erlang方面存在结构性问题。

这几乎总是会出现在令人困惑的代码和奇怪的边缘情况下,让你问自己诸如“如何检查空列表?”没有意识到你真正要问的是“如何检查一个空列表作为程序条件?”这是理智的函数式编程的祸根。

编辑:触摸更多的解释和一个例子可能是为了

无论你想注入模式匹配,你可以使用类似的情况下,也可以打破任何你正在做的出成单独的功能。很多时候,你会发现你的语义模糊不清,一方面你的工作过于紧密(你正在做的工作,而不是在receive内收到邮件),另一方面太松散(你参与其中在调用一个函数之前进行大量的任意程序检查,当真正匹配参数时是自然的解决方案)。

looper(V, ViewerSet) -> 
    receive 
    {From, set_value, V} -> 
     set_viewer_values(V, ViewerSet), 
     looper(V, ViewerSet); 
% OtherStuff -> 
%  whatever else looper/2 does... 
    end. 

set_viewer_values(V, [])  -> set_default_values(V); 
set_viewer_values(V, ViewerSet) -> 
    % ... whatever the normal function definition is... 

无论您从接受的内部调度到何种程度,都应该做实际的工作,这也是您希望进行匹配的地方。由于这是一个函数调用,无论如何,匹配在这里是非常合适的,并简化了你的代码。

如果你想匹配looper/2本身,这当然是可能的。我不知道你想,当你收到一个空列表做什么,所以我会弥补的东西,但你可以做任何你想要的:

looper(V, [])  -> looper(V, default_set()); 
looper(V, ViewerSet) -> 
    % As before, or whatever makes sense. 

你甚至可以决定,当你有一个空设置你需要在一个完全不同的方式来操作:

full_looper(V, [])  -> empty_looper(V); 
full_looper(V, ViewerSet) -> 
    receive 
    {new_set, Set} -> 
     looper(V, Set); 
    {From, set_value, V} -> 
     set_viewer_values(V, ViewerSet), 
     looper(V, ViewerSet) 
    end. 

empty_looper(V) -> 
    receive 
    {new_set, Set} -> 
     full_looper(V, Set); 
    {From, set_value, V} -> 
     set_viewer_values(V, default_set()), 
     empty_looper(V) 
    end. 

我的上述观点是,有许多方法来处理具有空集的情况下,而不是诉诸任意程序检查,并且所有的阅读更容易一次你知道你的方式(直到你习惯于这样做,但它可能会感觉很奇怪)。作为一个方面说明,最后一个例子实际上是创建一个有限状态机 - 并且有一个OTP模块已经可以使创建FSM变得非常简单。 (他们很容易手工编写二郎,太多,但即使有gen_fsm模块更容易。)

尝试Case to check when list is empty rather then recursion?

+0

那么你基本上说的是做到这一点? 'case ViewerSet empty_list - > looper(V,ViewerSet); [_] - > set_viewer_values(V,ViewerSet)' – sokras 2014-11-02 15:34:43

+0

我无法与活套进行模式匹配。我可以吗? – sokras 2014-11-02 15:47:47

+0

@sokras Erlang中随处可见模式匹配的机会,你只需要练习看看它们。我在上面添加了两个例子,一个在'set_viewer_values/2'中,另一个在'looper/2'本身。 – zxq9 2014-11-03 00:11:01

0

在两个if表达式,如果ViewerSetempty_set会发生什么?没有警卫来处理这种情况。

if Erlang中的表达式不是您在其他语言中看到的典型的if表达式。从我所拥有的经验来看,他们大多被避免,并且有一个很好的理由:(作为另一个已经提到的答案)模式匹配可以用来检查平等和其他比较操作(通过守卫)。

以下是here采取:

If no guard sequence is true, an if_clause run-time error will occur. If necessary, the guard expression true can be used in the last branch, as that guard sequence is always true.

Example:

is_greater_than(X, Y) -> 
    if 
     X>Y -> 
      true; 
     true -> % works as an 'else' branch 
      false 
    end 

所以if表达式最终会被排序case但布尔值作为他们的条款,他们往往比清晰引进更多的混乱。有些人甚至避免any usage of if expression

我的建议是,每当你看到自己使用if表达式时,问问自己如何用模式匹配来替换它,或者使用case或作为函数子句的一部分。

0

如果您有变量ViewerSet中的ID列表,只需用空列表初始化它:[]

然后,当收到消息{从,SET_VALUE,V}可以执行一个功能,用于使用列表中lists:foreach/2或使用列表解析(即使它是空的)的每一个元素:

{From, set_value, V} -> 
    lists:foreach(fun(ViewerPid) -> ViewerPid ! {self(), set_value, Value} end, ViewerSet), 
    looper(V, ViewerSet); 
... 

{From, set_value, V} -> 
    [fun(ViewerPid) -> ViewerPid ! {self(), set_value, Value} end || ViewerPid <- ViewerSet], 
    looper(V, ViewerSet); 
... 
0

基于您的代码,这是你应该得到什么:

([email protected])8> Val. 
myatom 
([email protected])9> if Val /= myatom -> lists:map(fun(X) -> io:format("~p",[X]) end, Val) end. 
** exception error: no true branch found when evaluating an if expression 
([email protected])10> 

所以看起来问题存在于别的地方。