Надежная уборка в Mathematica
Что бы там ни было, Mathematica предлагает множество конструкций, которые позволяют вам осуществлять нелокальную передачу контроля, включаяReturn
, Catch
/Throw
, Abort
а такжеGoto
, Однако такого рода нелокальные передачи управления часто вступают в конфликт с написанием надежных программ, которые должны обеспечивать выполнение кода очистки (например, закрытие потоков). Многие языки обеспечивают способы обеспечения выполнения кода очистки в самых разных ситуациях; У Java есть свояfinally
блоки, C ++ имеет деструкторы, Common Lisp имеетUNWIND-PROTECT
, и так далее.
В Mathematica я не знаю, как сделать то же самое. У меня есть частичное решение, которое выглядит так:
Attributes[CleanUp] = {HoldAll};
CleanUp[body_, form_] :=
Module[{return, aborted = False},
Catch[
CheckAbort[
return = body,
aborted = True];
form;
If[aborted,
Abort[],
return],
_, (form; Throw[##]) &]];
Это, конечно, не выиграет ни одного конкурса красоты, но это также только обрабатываетAbort
а такжеThrow
, В частности, он терпит неудачу при наличииReturn
; Я полагаю, если вы используетеGoto
чтобы сделать этот вид нелокального контроля в Mathematica, вы заслуживаете того, что получаете.
Я не вижу хорошего способа обойти это. Нет никакихCheckReturn
например, и когда вы получите прямо к этому,Return
имеет довольно темную семантику. Есть трюк, который я пропускаю?
РЕДАКТИРОВАТЬ: Проблема сReturn
и неопределенность в его определении связана с его взаимодействием с условными выражениями (которые в Mathematica почему-то не являются «структурами управления»). Пример, используя мойCleanUp
форма:
CleanUp[
If[2 == 2,
If[3 == 3,
Return["foo"]]];
Print["bar"],
Print["cleanup"]]
Это вернет «foo» без печати «cleanup». Точно так же,
CleanUp[
baz /.
{bar :> Return["wongle"],
baz :> Return["bongle"]},
Print["cleanup"]]
вернет "связку" без очистки печати. Я не вижу пути обхода этого без утомительного, подверженного ошибкам и, возможно, невозможного обхода кода или какого-то локального переопределенияReturn
с помощьюBlock
, который ужасно хакерский и на самом деле не работает (хотя экспериментировать с ним - отличный способ полностью заклинить ядро!)