0

Я пытаюсь написать функцию, которая получает список, находит наивысшее значение целое в списке, а затем делит все остальные целые числа в списке на это значение.Как проверить, где мой код застрял в Erlang?

К сожалению, мой код застрял где-то. Если бы это был python, например, я мог бы легко написать пару разных «печатных изданий» и посмотреть, где он застрял. Но как вы это делаете в Эрланге?

Вот код.

highest_value([], N) -> 
    if 
     N =:= 0 -> 
      'Error! No positive values.' 
    end, 
    N; 
highest_value([H|T], N) when H > N, H > 0 -> 
    highest_value([T], H); 
highest_value([_|T], N) -> 
    highest_value([T], N). 

divide(_L) -> [X/highest_value(_L, 0) || X <- _L]. 
+1

Обратите внимание, что ваш '/ функция деления 1' нерационально пересчитывает наибольшее значение в список для каждого элемента, обработанного в понимании списка. Вы должны сначала называть 'high_value (_L, 0)', привязать его возвращаемое значение к переменной и использовать переменную в качестве делителя в понимании списка. –

ответ

2

Для печати вы можете использовать только io:format/2. То же самое.

highest_value([H|T], N) when H > N, H > 0 -> 
    io:format(">>> when H bigger than N~n"), 
    io:format(">>> H: ~p, T: ~p, N: ~p ~n", [H, T, N]), 
    highest_value([T], H); 
highest_value(List) -> 
    highest_value(List, 0). 

EDIT

Одна вещь, вы получаете неправильно это [H | T] синтаксис. H, или head, является первым элементом в списке. T означает «хвост» или «остаток списка». И, как видно из названия, tail - это список (может быть пустой список, но список тем не менее). Поэтому, когда вы делаете рекурсию, вам не нужно вставлять T в новый список.

highest_value([H|T], N) when H > N -> 
    highest_value(T, H); 

highest_value([_|T], N) -> 
    highest_value(T, N). 

В вашем старом коде, называется:

highest_value([T], N). 

, который создал новый список с одним элементом, как [[2,3,4,5]]. Если вы возглавляете этот хвост, вы получаете этот список только-element как головку, а пустой список - как хвост.


Кроме того, в первом предложении функции вы имеете атома 'Error! No positive values.' (опалить котировки означает, что это просто длинный атом, а не строка), которая никогда не возвращается (вы всегда будете возвращаться N). Если вы хотели бы вернуть либо некоторый атом, или N, в зависимости от значения N вы могли бы просто расширить использование функциональных положений

highest_value([], 0) -> 
    'Error! No positive values.' 
highest_value([], N) -> 
    N; 
[...] 

И вы должны инициализировать функцию с 0, которые можно было бы считать плохим шаблон. Вы можете написать и использовать highest_value/1, который делает это для вас

highest_value(List) -> 
    highest_value(List, 0). 

Или даже использовать модификацию этого алгоритма: поскольку наибольшее число будет одним из номеров в списке, вы можете использовать первый элемент в качестве функции инициализация.

highest_value(_List = [First|T]) when First > 0 -> 
    highest_value(T, First). 

Это предполагает, что обработка отрицательных чисел - это то, что вам сейчас неинтересно.

+0

Я внесла некоторые изменения в код, я не мог применить все, что вы упомянули. Но вот обновленная версия кода. Он все еще висит. 'high_value ([], N), когда N = < 0 -> 'Ошибка! Нет положительных значений. '; высшая_значение ([], N) при N> 0 -> N; high_value ([H | T], N), когда H> N -> high_value ([T], H); high_value ([_ | T], N) -> high_value ([T], N). normalize (_L) -> [X/high_value (_L, 0) || X <- _L]. '@ Mpm Я думаю, что он зависает, когда есть только один элемент, который нужно проверить. Но я не знаю, как это решить :( –

+0

По-прежнему с той же ошибкой, и все же я считаю, что вы можете найти ее с помощью 'io: format''ing. Если нет, пинговать меня снова. – mpm

+0

Хорошо, похоже список не разбивает список после итерации. Я действительно не знаю, как это исправить. '>>> когда Н больше N >>> H: 1, T: [2,3,4 , 5], N: 0 >>> когда Н больше N >>> H: [2,3,4,5], T: [], N: 1 ' @mpm –

1

Хотя отладка с помощью заявлений печати является обычной и даже иногда полезной, и для этой цели можно использовать io:format, Erlang as already noted, Erlang предоставляет мощные встроенные функции трассировки, которые вы должны использовать вместо этого.

Предположим, что ваши функции highest_value/2 и divide/1 находятся в модуле с именем hv.Во-первых, мы собираем hv в оболочке Эрланга:

1> c(hv). 
{ok,hv} 

Далее мы используем Erlang's dbg module для включения трассировки на hv функции:

2> dbg:tracer(). 
{ok,<0.41.0>} 
3> dbg:p(self(),call). 
{ok,[{matched,[email protected],26}]} 
4> dbg:tpl(hv,c). 
{ok,[{matched,[email protected],5},{saved,c}]} 

В команде 2 мы включить трассировку отладки и в команде 3 мы указываем что мы хотим отслеживать вызовы функций в нашем текущем процессе (возвращается self()). В команде 4 мы создаем трассировку вызова с использованием встроенной спецификации трассировки c по всем функциям модуля hv.

После трассировка отладки включена, мы называем hv:divide/1 и начинается вывод трассировки:

5> hv:divide([4,8,12,16]). 
(<0.34.0>) call hv:divide([4,8,12,16]) ({erl_eval,do_apply,6}) 
(<0.34.0>) call hv:'-divide/1-lc$^0/1-0-'([4,8,12,16],[4,8,12,16]) ({erl_eval, 
                    do_apply, 
                    6}) 
(<0.34.0>) call hv:highest_value([4,8,12,16],0) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([[8,12,16]],4) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([[]],[8,12,16]) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([[]],[8,12,16]) ({hv,'-divide/1-lc$^0/1-0-',2}) 
... 

Во-первых, обратите внимание, что я сокращенный вывод трассировки, потому что в ... момент это уже в бесконечном цикле, а остальные трассы идентичны двум утверждениям до ....

Что говорит нам трассировка? В первой строке отображается вызов функции divide/1, а во второй строке показан вызов для понимания списка внутри divide/1. Затем мы видим звонки на номер highest_value/2, сначала с полным списком и N, равным 0. Следующий вызов, где он становится интересным: потому что ваш код проходит [T], а не T в качестве первого аргумента в рекурсивном вызове highest_value/2, H имеет значение [8,12,16], который лечит Эрланга как больше, чем текущее значение N 4, так что следующий рекурсивный вызов является:

highest_value([T], [8,12,16]). 

и потому, что это T[], это превращается в:

highest_value([[]], [8,12,16]). 

Здесь H - [], а T - также []. H не больше [8,12,16], поэтому все оставшиеся рекурсивные вызовы после этой точки идентичны этому, а рекурсия бесконечна.

Чтобы это исправить, вам необходимо пройти T правильно as already noted:

highest_value([H|T], N) when H > N, H > 0 -> 
    highest_value(T, H); 
highest_value([_|T], N) -> 
    highest_value(T, N). 

Перекомпилируйте, который также перезагружает ваш модуль, и из-за того, что вам также необходимо настроить отладку трассировки снова:

5> c(hv). 
{ok,hv} 
6> dbg:tpl(hv,c). 
{ok,[{matched,[email protected],5},{saved,c}]} 
7> hv:divide([4,8,12,16]). 
(<0.34.0>) call hv:divide([4,8,12,16]) ({erl_eval,do_apply,6}) 
(<0.34.0>) call hv:'-divide/1-lc$^0/1-0-'([4,8,12,16],[4,8,12,16]) ({erl_eval, 
                    do_apply, 
                    6}) 
(<0.34.0>) call hv:highest_value([4,8,12,16],0) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([8,12,16],4) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([12,16],8) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([16],12) ({hv,'-divide/1-lc$^0/1-0-',2}) 
(<0.34.0>) call hv:highest_value([],16) ({hv,'-divide/1-lc$^0/1-0-',2}) 
** exception error: no true branch found when evaluating an if expression 
    in function hv:highest_value/2 (/tmp/hv.erl, line 5) 
    in call from hv:'-divide/1-lc$^0/1-0-'/2 (/tmp/hv.erl, line 15) 

Трассировка теперь показывает, что highest_value/2 работает, как ожидалось, но теперь мы попали новые проблемы с if заявление, и исправить это уже объяснено in another answer, поэтому я не буду повторять его здесь.

Как вы можете видеть, трассировка Erlang намного мощнее, чем использование «отладки печати».

  • Он может быть включен и выключен интерактивно в оболочке Erlang по мере необходимости.
  • В отличие от отладки других языков, трассировка отладки не требует специальных флагов компиляции для ваших модулей.
  • В отличие от отладочных операторов печати, вам не нужно менять код и повторно перекомпилировать.

То, что я показал здесь, едва царапает поверхность до тех пор, пока возможности трассировки Erlang не исчезнут, но этого было более чем достаточно, чтобы найти и исправить проблемы.

И, наконец, обратите внимание, что при использовании lists:max/1 стандартной библиотеки вызова вы можете легко добиться того, что ваш модуль пытается сделать:

divide(L) -> 
    case lists:max(L) of 
     N when N > 0 -> 
      [V/N || V <- L]; 
     _ -> 
      error(badarg, [L]) 
    end. 
Смежные вопросы