erlang - 如何在 Erlang 中检查列表是否为空?

标签 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)
  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 表达式我必须检查列表是否为空,但它仍然尝试映射它。

那么我的表达式做错了什么?

谢谢

最佳答案

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

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

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

无论你想在哪里注入(inject)模式匹配,你都可以使用类似 case 的东西,或者你可以将你正在做的任何事情分解成一个单独的函数。通常,您会发现语义模糊,一方面事物耦合得太紧密(您正在做的工作不是在 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 变得非常容易。 (它们也很容易在 Erlang 中手动编写,但使用 gen_fsm 模块更容易。)

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

关于erlang - 如何在 Erlang 中检查列表是否为空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26700321/

相关文章:

python - pyparsing:字典列表的语法(erlang)

sockets - tcp 服务器和客户端交互

erlang - 如何读取文件中的 dbg 二进制输出?

erlang - 如何连接在网络中不同主机上运行的两个 Erlang 节点?

erlang - 如何知道erlang中节点的id

erlang - 我可以在另一个应用程序或模块中使用现有的 OTP 应用程序吗?

ubuntu - 在 native 模式下运行 erlang 代码

automated-tests - 如何在 eunit 中使用 debugMsg 以及如何在 eunit 测试中打印一些内容,尽管测试超时

Erlang 函数名称在运行时被更改

networking - Erlang节点连接超时