Как отлаживать при написании маленьких или больших кодов с помощью Mathematica? верстак? мма отладчик? или что-то другое?

На mathkb.com я нашел интересный пост "Еще один обзор отладчика Mathematica" (автор Berniethejet), в котором говорится об отладке в wolfram workbench.

http://www.mathkb.com/Uwe/Threads/List.aspx/mathematica/20986

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

  1. Является ли верстак настоящим отладчиком, но наблюдателем? в чем его преимущество перед mathematica?
  2. Как вы отлаживаете, когда пишете большие или маленькие коды? mabye workbench для отладки небольших кодов и отладчика mma для больших кодов?
  3. Есть ли какие-либо предложения по отладке как для пользователей с легкими, так и с тяжелыми математиками?

Ответы

Ответ 1

Отладчики обычно более полезны, когда вы программируете в стиле stateful (переменные, назначения и т.д.) - по крайней мере, это был мой опыт. Для идиоматического программирования Mathematica (функционально-основанного на правилах) некоторые версии операторов Print не менее эффективны. Вы можете посмотреть эту статью для некоторых вариантов утилиты отладки печати. Я запишу свою версию, взятую из this Сообщение Mathgroup.

SetAttributes[ShowIt, HoldAll];
ShowIt[code_] :=
  Module[{y},
    Print[ToString[Unevaluated[code]], " = ", y = code];
    y]; 

Идея состоит в том, что вы можете вставить такой вызов функции в "трубу" вызовов функций - он печатает значение, а затем передает его следующей (окружной) функции. В качестве простого примера:

In[29]:= Map[#^2&,[email protected][Range[10],EvenQ]]
During evaluation of In[29]:= Select[Range[10], EvenQ] = {2,4,6,8,10}

Out[29]= {4,16,36,64,100}

Это должно работать нормально в большинстве случаев (за исключением, возможно, тех, где окружающая функция содержит свои аргументы и действует на них нетривиально). Одной из причин, по которой этот подход очень эффективен в Mathematica, является то, что функциональное программирование приводит к программам, в которых (почти) каждая часть имеет смысл сама по себе - поскольку результат одной функции обычно передается непосредственно в прилагаемую функцию.

Тем не менее, вы можете использовать отладчик, как в интерактивном сеансе, так и в WorkBench, используя режим "Debug As Mathematica". В то время как я сам использую WorkBench сам, я никогда не нашел это необходимым, но YMMV.

Другим замечательным средством, которое помогает много, является встроенная команда Trace. Я рекомендую прочитать документацию на нем - он имеет ряд дополнительных опций и может быть настроен, чтобы помочь многим. Я приведу один простой, но нетривиальный пример: отслеживание выполнения алгоритма mergesort со следующей (упрощенной) реализацией:

Clear[merge];
merge[{}, {x__}] := {x};
merge[{x__}, {}] := {x}
merge[{x__?NumericQ}, {y__?NumericQ}] /; First[{x}] <= First[{y}] := 
  Flatten[{First[{x}], merge[Rest[{x}], {y}]}];
merge[{x__?NumericQ}, {y__?NumericQ}] := merge[{y}, {x}];

Clear[mergesort];
mergesort[x : {} | {_}] := x;
mergesort[x : {__?NumericQ}] := 
 With[{splitlen = IntegerPart[Length[x]/2]}, 
   merge[mergesort[Take[x, splitlen]], mergesort[Drop[x, splitlen]]]]

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

In[41]:= testlst = RandomInteger[10, 5]

Out[41]= {0, 6, 9, 8, 8}

Вы можете просто использовать Trace[mergesort[testlst]];, но вывод не очень легко читать, так как он содержит все этапы. Используя

In[42]:= Trace[mergesort[testlst],_mergesort]

Out[42]= {mergesort[{0,6,9,8,8}],{mergesort[{0,6}],{mergesort[{0}]},
{mergesort[{6}]}},{mergesort[{9,8,8}],{mergesort[{9}]},{mergesort[{8,8}],
{mergesort[{8}]},{mergesort[{8}]}}}}

Вы получаете очень четкую картину рекурсивных вызовов функций. Вы можете пойти глубже и проследить динамику функции merge. Для этого вам нужно обработать результат Trace (который также является выражением Mathematica!):

In[43]:= 
Cases[Trace[mergesort[testlst],_merge],merge[x__List]/;FreeQ[{x},mergesort]:> 
 HoldForm[merge[x]],Infinity]

Out[43]= {merge[{0},{6}],merge[{},{6}],merge[{8},{8}],merge[{},{8}],
merge[{9},{8,8}],merge[{8,8},{9}],merge[{8},{9}],merge[{},{9}],merge[{0,6},
{8,8,9}],merge[{6},{8,8,9}],merge[{},{8,8,9}]}

Этот последний пример иллюстрирует, что даже когда трудно сконфигурировать Trace, чтобы отфильтровывать нежелательные этапы выполнения, можно просто выполнить пост-обработку результатов Trace, используя стандартные средства, которые Mathematica обеспечивает для деструктурирования выражения (например, как Cases).

Позвольте мне также упомянуть, что пользователь и консультант Mathematica Дэвид Бэйли написал пакет DebugTrace, который должен быть альтернативой отладчик. У меня еще не было возможности попробовать, но я уверен, что стоит попробовать.

Наконец, хотя это не связано напрямую с отладкой, WorkBench имеет интегрированную модульную систему тестирования MUnit, которую я нашел очень полезной. Он аналогичен по духу хорошо известным модульным модулям тестирования на других языках, таких как JUnit для Java. Для крупномасштабного развития это может быть реальной помощью.

Что касается использования WorkBench, я бы сказал, что он действительно рассчитывает использовать его для чего угодно, кроме самых маленьких проектов (или даже для них). Он основан на Eclipse, и вы получаете такие же приятные вещи, как редактор с подсветкой кода, "перейти к определению функции", навигации, поиска, интеграции CVS/SVN и т.д. В то же время вы не теряют почти что-либо с точки зрения интерактивности - вы все же можете развить новую функциональность в интерактивной сессии Mathematica, связанной с WorkBench при работе в режиме "Run as Mathematica". Для больших проектов, связанных с множеством пакетов, я просто не вижу причин не использовать его.

Ответ 2

Использование отладчика в Wolfram Workbench делает отладку простой и эффективной. Причина, по которой я начал использовать Workbench, был отладчиком. Workbench также поддерживает MUnit Mathematica вариант JUnit. - "Сначала проверьте, затем код".

Отладчик в Workbench поддерживает все, что я ожидал от отладчика. Я использовал отладчики Java в Eclipse и NetBeans.

По крайней мере, попробуйте отладчик, чтобы вы могли сравнить. На сайте Workbench Docs есть учебное пособие.

Ответ 3

Вот некоторые варианты ShowIt, описанные Леонидом. Определение их в системном контексте позволяет легко использовать их в пакетах.

SetAttributes[System`ShowIt, HoldAll];
System`ShowIt[code__] := System`ShowIt[{code}];
System`ShowIt[code_] :=
   With[{y = code},
      Print[Defer[code = y]];
      y
   ]; 

SetAttributes[System`PrintIt, {HoldAll,Listable}];
System`PrintIt[expr__]:=System`PrintIt[{expr}];
System`PrintIt[expr_] := System`ShowIt[expr];

Пример:

ShowIt[{x=2,x=3}]
PrintIt[{x=2,x=3}]

Выход этих функций можно легко повторно использовать в интерфейсе, изменив его стиль на "Вход".

Ответ 4

У меня был ограниченный успех с отладчиком, в основном потому, что я не нашел времени, чтобы его изучить. Я часто использую одну технику. Вместо того, чтобы прибегать к операторам печати, я делаю выражения под моим манипулятором (или любым другим) формы Dynamic [var]. В этом случае вы можете легко контролировать любую глобальную переменную файла в реальном времени без генерации огромного объема. Чтобы увидеть, как манипулировать переменными, используйте LocalizeVariables- > False и делайте то же самое. Вне контекста манипуляции переменные видны, но не динамичны; их мониторинг, таким образом, тот же.