我发现那些功能结果不能用于防护,所以我使用了case.这导致嵌套的case语句
case Destination <1 of
true -> {ok,NumberOfJumps+1};
false ->
case lists:flatlength(A)
doSomething;
false ->
case lists:member(Destination,VisitedIndices) of
true -> doSomething;
false ->
doSomethingElse
end
end
end.
我发现这在可读性和代码风格方面很糟糕.这是你如何在erlang中做这样的事情,还是有更优雅的方式来做到这一点?
提前致谢
1> zxq9..:
在你将以下内容作为一些神奇的福音之前,请注意输入此功能的方式几乎肯定是单一的.你应该在达到这一点之前设法限制案例 - 对嵌套案例的需求本身通常是代码味道.有时它确实是不可避免的,但我强烈怀疑这个方法的某些方面可以在代码中更早地简化(特别是考虑到传递的数据结构以及它们的含义).
没有看到变量A
的来源,我在这里作为一个参数.另外,在没有看到这个函数是如何进入的情况下,我正在编写一个函数头,因为没有剩下的函数可以通过它很难说肯定.
尽管如此,让我们稍微重构一下:
首先,我们想要摆脱我们知道可以进入后卫的一件事,那是你第一次case
检查是否Destination <1
.让我们考虑一下我们真的想要调用一个共同函数的两个不同的子句,而不是使用一个案例:
foo(Destination, NumberOfJumps, _, _) when Destination <1 ->
{ok, NumerOfJumps + 1};
foo(Destination, _, VisitedIndices, A) ->
case lists:flatlength(A) doSomething;
false ->
case lists:member(Destination,VisitedIndices) of
true -> doSomething;
false ->
doSomethingElse
end
end.
不太奇怪.但那些仍然存在的嵌套案例......对他们来说很烦人.这是我怀疑可以在其他地方做些什么来减轻代码中更早出现的路径选择的地方.但是让我们假装你无法控制那些东西.在这种情况下,布尔值和if
a的分配可以是可读性增强器:
foo(Destination, NumberOfJumps, _, _) when Destination <1 ->
{ok, NumberOfJumps + 1};
foo(Destination, _, VisitedIndices, A) ->
ALength = lists:flatlength(A) fun doSomething/0;
AMember -> fun doSomething/0;
not AMember -> fun doSomethingElse/0
end,
NextOp().
在这里,我只是切入追逐并确保我们只通过将结果分配给变量来执行每次可能昂贵的操作 - 但这让我非常不舒服,因为我不应该在这种情况下开始.
在任何情况下,像这样的东西应该测试与前面的代码相同,并且在过渡期间可能更具可读性.但你应该寻找其他地方来简化.特别是,这个VisitedIndices
业务感觉很可疑(为什么我们不知道是否Destination
是会员?),A
在我们到达这个功能后需要变平的变量很奇怪(为什么它还没有被压扁?为什么会这样?大部分?),NumberOfJumps
感觉就像一个累积器,但它的存在是神秘的.
你可能会问,是什么让我对这些变量感到奇怪?唯一一直使用的是Destination
- 其他只用于一个foo/4
或另一个的子句,但不是两者都使用.这让我觉得这应该是在执行链的某个地方进行的不同执行路径,而不是在超级决策 - o-matic类型函数中进行清理.
编辑
通过更全面地描述手头的问题(参考下面评论中的讨论),考虑一下如何解决这个问题:
-module(jump_calc).
-export([start/1]).
start(A) ->
Value = jump_calc(A, length(A), 1, 0, []),
io:format("Jumps: ~p~n", [Value]).
jump_calc(_, Length, Index, Count, _) when Index <1; Index > Length ->
Count;
jump_calc(Path, Length, Index, Count, Visited) ->
NewIndex = Index + lists:nth(Index, Path),
NewVisited = [Index | Visited],
NewCount = Count + 1,
case lists:member(NewIndex, NewVisited) of
true -> NewCount;
false -> jump_calc(Path, Length, NewIndex, NewCount, NewVisited)
end.
始终尝试尽可能多地进行前端加载,而不是一遍又一遍地执行相同的计算.考虑一下我们可以很容易地阻止守卫背后的每一次迭代,以及我们甚至不必编写多少有条件的东西.功能匹配是一个强大的工具 - 一旦掌握了它,你将真正开始享受Erlang.