基本上我有一个结构,包括一个值和一个ID列表.我想做的是Map到ID列表,并发送消息给他们,但当我第一次初始化ID列表时,我把变量“empty_set”.(也许我应该重命名为empty_list:P).
问题是,每当我调用map函数时,我想先检查列表是否为“empty_set”,如果不是,就在列表中使用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表达式来检查列表是否为空,但它仍然试图Map列表。
那么,我的表达有什么不对吗?
谢谢
4条答案
按热度按时间jbose2ul1#
模式匹配:如果你需要检查guard或者
if
或者cond
中的空列表,那么几乎可以肯定你对Erlang的思考方式存在结构性问题。这几乎总是表现在令人困惑的代码和奇怪的边缘情况中,让你问自己“我如何检查一个空列表?”而没有意识到你真正在问的是“我如何检查一个空列表 * 作为一个过程条件 *?”这是健全的函数式编程的祸根。
编辑:可能需要更多说明和示例
无论你想在哪里注入模式匹配,你都可以使用像case这样的东西,或者你可以把你正在做的事情分解成一个单独的函数。你经常会发现,一方面,你有一个语义模糊的地方,事情耦合得太紧密了(您正在
receive
中执行除接收消息以外的工作),另一个则过于松散(在调用函数之前,您要进行大量的任意过程检查,而实际上参数匹配是自然的解决方案)。无论你从receive中将数据发送到哪里,都是应该做实际工作的地方,也是你想要做匹配的地方,因为这是一个函数调用,无论如何匹配在这里是一个很好的选择,并且简化了你的代码。
如果你想在
looper/2
中进行匹配,这当然是可能的。我不知道当你收到一个空列表时你想做什么,所以我会做一些事情,但是你可以做任何你想做的事情:你甚至可以决定,当你有一个空集时,你需要用一种完全不同的方式来操作:
我在上面的观点是,有许多方法可以处理空集的情况,而无需诉诸任意的过程性检查,并且一旦您了解了方法,所有这些方法都更容易阅读(不过,在你习惯这样做之前,这会感觉相当奇怪)。作为一个侧记,最后一个例子实际上是创建一个有限状态机--已经有一个OTP模块可以使创建FSM变得非常容易。(用Erlang手工编写它们也很容易,但使用
gen_fsm
模块更容易。)当列表为空时,尝试Case检查而不是递归检查?
dwbf0jvd2#
在这两个
if
表达式中,如果ViewerSet
是empty_set
,会发生什么?没有处理这种情况的保护。Erlang中的
if
表达式并不是其他语言中常见的if
表达式,从我的经验来看,大多数情况下都会避免使用它们,这是有原因的:(作为已经提到的另一个答案)模式匹配可以用于检查相等性和其他比较操作(通过保护)。以下内容摘自此处:
如果没有保护序列为真,则会发生
if_clause
运行时错误。如果需要,可以在最后一个分支中使用保护表达式true
,因为该保护序列始终为真。示例:
所以
if
表达式最终是case
的一种,但是用布尔值作为子句,它们往往会引入更多的混乱而不是清晰,有些人甚至避免使用if
表达式。我的建议是,每当您看到自己在使用
if
表达式时,问问自己如何用模式匹配替换它,或者用case
替换,或者作为函数子句的一部分。wfveoks03#
如果变量
ViewerSet
中有一个id列表,只需使用空列表初始化它:[]
.然后,当你收到消息{From,set_value,V}时,你可以使用
lists:foreach/2
或列表解析为列表的每个元素执行一个函数(即使它是空的):或
wb1gzix04#
根据您的代码,您应该得到以下内容:
看来问题出在别的地方。