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

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

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

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

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

Заранее спасибо. Вы, ребята в SO, всегда очень полезны.:)

4 ответа

Решение

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

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

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

In[29]:= Map[#^2&,ShowIt@Select[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. Я рекомендую прочитать документацию по нему - он имеет ряд дополнительных опций и может быть настроен, чтобы помочь много. Я приведу один простой, но нетривиальный пример: отслеживание выполнения алгоритма сортировки слиянием со следующей (упрощенной) реализацией:

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, при работе в режиме "Запуск от Mathematica". Для больших проектов, включающих много пакетов, я просто не вижу причин не использовать его.

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

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

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

Вот несколько вариаций 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}]

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

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

Другие вопросы по тегам