基本上,我有一个包含值和 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 表达式我必须检查列表是否为空,但它仍然尝试映射它。
那么我的表达式做错了什么?
谢谢
最佳答案
模式匹配。如果您需要检查守卫或 if
或 cond
中的空列表,那么几乎可以肯定您对 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
模块更容易。)
关于erlang - 如何在 Erlang 中检查列表是否为空?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26700321/