Перед тем, как принять следующий как некое магическое Евангелие, обратите внимание, что путь эта функция вводится почти наверняка unidiomatic. Вы должны стремиться ограничивать случаи до того, как вы доберетесь до этого момента - потребность в вложенных случаях сама по себе является запахом кода. Иногда это действительно неизбежно, но я сильно подозреваю, что некоторые аспекты этого могут быть упрощены ранее в коде (особенно с некоторыми соображениями, данными о структурах данных, которые передаются и что они означают).
Не видя, откуда идет переменная A
, я делаю ее здесь как параметр. Кроме того, не видя, как эта функция была введена, я составляю функцию, потому что без остальной функции, которую нужно выполнить, довольно сложно сказать что-либо точно.
С учетом всего сказанного, давайте реорганизовать это немного:
Прежде всего, мы хотим, чтобы избавиться от одной вещи, которую мы знаем, может пойти в охранника, и это ваш первый case
, который проверяет, является ли Destination < 1
. Вместо того, чтобы использовать случай, давайте рассмотрим, что мы действительно хотим, чтобы назвать два разных положения о единой функции:
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.
Не слишком странно. Но те вложенные случаи, которые остаются ... что-то раздражает их. Вот где я подозреваю, что что-то можно сделать в другом месте, чтобы облегчить выбор путей, которые здесь делаются намного раньше в коде. Но давайте притворимся, что у вас нет контроля над этим. В этой ситуации уступки булевы и if
может быть читаемость энхансер:
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().
Здесь я просто вырезать в погоню и убедились, что мы только выполнить каждый потенциально дорогостоящую операцию один раз, присваивая результат переменной - но это делает меня очень неудобным, потому что я не должен быть в этой ситуации для начала.
В любом случае, что-то вроде этого должно протестировать то же, что и предыдущий код, и в промежуточный период может быть более читаемым. Но вы должны искать другие места для упрощения. В частности, этот бизнес чувствует себя подозрительным (почему бы нам не знать, является ли Destination
членом?), Переменная A
, нуждающаяся в том, чтобы быть сплющенной после того, как мы прибыли в эту функцию, является нечетной (почему она еще не сглажена? есть ли так много?), и NumberOfJumps
чувствует что-то вроде аккумулятора, но его присутствие таинственно.
Что заставляет меня чувствовать себя странно об этих переменных, вы можете спросить? Единственный, который постоянно используется, - Destination
- остальные используются только в одном пункте foo/4
или другом, но не для обоих.Это заставляет меня думать, что это должны быть разные пути исполнения где-то дальше по цепочке исполнения, а не все, что происходит здесь, в функции супер-решения-о-матичного типа.
EDIT
С полным описанием проблемы в руке (ссылка на обсуждение в комментариях ниже), рассмотрим, как это работает:
-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.
Всегда старайтесь передней нагрузки, как много возможно, вместо того, чтобы выполнять один и тот же расчет снова и снова. Подумайте, как легко мы можем задержать каждую итерацию за охранниками, и сколько условных вещей нам даже не нужно писать из-за этого. Совпадение функций - мощный инструмент - как только вы его повесите, вы действительно начнете наслаждаться Эрланг.
Только немного больше кода, например, как эта функция вводится, может быть полезной, чтобы помочь вам определить странность. – zxq9