如何检查Erlang中的列表是否为空?

如何检查Erlang中的列表是否为空?,erlang,erlang-shell,Erlang,Erlang Shell,基本上,我有一个包含值和ID列表的结构。 我想做的是映射ID列表并向它们发送消息,但当我第一次初始化ID列表时,我将变量“empty_set.”(也许我应该将其重命名为empty_list:P) 问题是,每当我调用map函数时,我都想首先检查列表是否为“空集”,如果不是,则使用其中的map函数。代码如下: {From, set_value, V} -> if ViewerSet /= empty_set -> set_viewer_values(V, ViewerSet) e

基本上,我有一个包含值和ID列表的结构。 我想做的是映射ID列表并向它们发送消息,但当我第一次初始化ID列表时,我将变量“empty_set.”(也许我应该将其重命名为empty_list:P)

问题是,每当我调用map函数时,我都想首先检查列表是否为“空集”,如果不是,则使用其中的map函数。代码如下:

{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}]}]}
=错误报告===2014年11月2日::15:03:07===
使用退出值处理时出错:{function_子句,[{列表,映射,
[#Fun,empty_set],{file,“lists.erl”},{line,1223}]},{lists,map,2,
[{file,“lists.erl”},{line,1224}]},{sheet,cell_循环,2,[{file,“sheet.erl”},{line,93}]}
据我所知,尽管if表达式必须检查列表是否为空,但它仍然试图映射到它上面

那么我对这个表达有什么错呢


谢谢

模式匹配。如果您需要检查guard中的空列表或
If
cond
几乎可以肯定,您对Erlang的思考方式存在结构性问题

这几乎总是表现在混乱的代码和奇怪的边缘情况中,让你问自己“我如何检查空列表?”而没有意识到你真正要问的是“我如何检查空列表作为过程条件?”这是理智函数式编程的祸根

编辑:可能需要更多的解释和示例

无论您想在何处注入模式匹配,都可以使用case之类的东西,也可以将正在执行的任何操作分解为一个单独的函数。通常情况下,您会发现语义上存在歧义,一方面事物之间的耦合过于紧密(您在
接收
中执行的工作不是接收消息),另一方面又过于松散(在调用函数之前,您需要进行大量的任意过程检查,而真正匹配参数是自然的解决方案)

无论您从receive中分派到何处,都应该执行实际工作,这也是您希望执行匹配的地方。因为这是一个函数调用,所以这里的匹配非常适合,并简化了代码

如果你想在
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变得非常简单。(它们也很容易用Erlang手工编写,但使用
gen_fsm
模块更容易。)


在两个
if
表达式上尝试,如果
ViewerSet
空集
,会发生什么情况?没有防护装置处理此情况

Erlang中的
if
表达式不是您在其他语言中看到的典型
if
表达式。从我的一点经验来看,它们基本上是可以避免的,并且有一个很好的理由:(正如前面提到的另一个答案)模式匹配可以用于检查相等性和其他比较操作(通过保护)

以下资料摘自:

如果没有保护序列为true,则将发生
If_子句
运行时错误。如有必要,保护表达式
true
可用于最后一个分支,因为该保护序列始终为true

例如:

is_greater_than(X, Y) ->
    if
        X>Y ->
            true;
        true -> % works as an 'else' branch
            false
    end
因此,
如果
表达式最终成为一种
大小写
,但以布尔值作为子句,它们往往会带来更多的混乱而不是清晰。有些人甚至会避免


我的建议是,每当您看到自己在使用
if
表达式时,问问自己如何用模式匹配替换它,可以是
大小写
,也可以是function子句的一部分。

如果变量
ViewerSet
中有一个ID列表,只需使用空列表对其进行初始化:
[]

然后,当您收到消息{From,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_值,V}->

[fun(ViewerPid)->ViewerPid!{self(),set_value,value}end | | ViewerPid根据您的代码,这是您应该得到的:

(shell@a)8> Val.
myatom
(shell@a)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
(shell@a)10> 

因此,问题似乎存在于其他地方。

那么您基本上是说这样做?
空列表的case ViewerSet->looper(V,ViewerSet);[\u]->设置视图值(V,ViewerSet)
我无法与活套进行模式匹配。可以吗?@sokras模式匹配机会在Erlang随处可见,你只需练习查看它们。我在上面添加了两个示例,一个在
设置查看器值/2
中,另一个在
活套/2
本身中。
{From, set_value, V} ->
  [fun(ViewerPid) -> ViewerPid ! {self(), set_value, Value} end || ViewerPid <- ViewerSet],
  looper(V, ViewerSet);
...
(shell@a)8> Val.
myatom
(shell@a)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
(shell@a)10>