Before you accept the following as some kind of magical gospel, note that the way you enter this function is almost certainly uniomatic. You should strive to limit cases before you get to this point - the need for nested cases is in itself a smell of code. Sometimes this is really inevitable, but I strongly suspect that some aspects of this can be simplified earlier in the code (especially with some considerations, data about the data structures that are transmitted and what they mean).
Without seeing the variable A , I am doing it here as a parameter. In addition, without seeing how this function was introduced, I compose the function, because without the rest of the function that needs to be executed, it is rather difficult to say anything for sure.
With all that being said, let a little reorganize this:
First of all, we want to get rid of what we know, can enter the guard, and this is your first case , which checks if Destination < 1 . Instead of using a case, consider what we really want to name two different sentences of a common function:
foo(Destination, NumberOfJumps, _, _) when Destination < 1 -> {ok, NumerOfJumps + 1}; foo(Destination, _, VisitedIndices, A) -> case lists:flatlength(A) < Destination of true -> doSomething; false -> case lists:member(Destination,VisitedIndices) of true -> doSomething; false -> doSomethingElse end end.
Not too weird. But those nested cases that remain ... something annoys them. This is where I suspect that something can be done elsewhere to facilitate the selection of paths that are made here much earlier in the code. But let it pretend that you have no control over it. In this situation, the assignment of Boolean and if can be an amplifier for readability:
foo(Destination, NumberOfJumps, _, _) when Destination < 1 -> {ok, NumberOfJumps + 1}; foo(Destination, _, VisitedIndices, A) -> ALength = lists:flatlength(A) < Destination, AMember = lists:member(Destionation, VisitedIncides), NextOp = if ALength -> fun doSomething/0; AMember -> fun doSomething/0; not AMember -> fun doSomethingElse/0 end, NextOp().
Here, I just cut the chase and made sure that we perform each potentially expensive operation once, assigning the result to a variable - but this makes me very uncomfortable, because I should not be in this situation for a start.
In any case, something like this should test the same as the previous code, and in the interim can be more readable. But you should look for other places to simplify. In particular, this VisitedIndices business seems suspicious (why don't we know if Destination member?), Variable A , which needs to be aligned after we arrive at this function, is odd (why is it not flattened, why is it so a lot?), and NumberOfJumps feels something like a battery, but its presence is mysterious.
What makes me feel weird about these variables, you ask? The only thing that is constantly used is Destination - the rest are used only in one foo/4 section or in the other, but not both. This makes me think that these should be different execution paths somewhere further down the execution chain, and not everything that happens here in a super-decision-o-math type function.
EDIT
For a more complete description of the problem (refer to the discussion in the comments below), consider how this happens:
-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.
Always try to load as much information as possible, rather than perform the same calculations over and over. Think about how easily we can delay each iteration behind the guards, and how much conditional material we donβt even need to write because of this. Matching is a powerful tool - once you hang it, you really start to enjoy Erlang.