Отличный вопрос, но я не согласен с тем, что семантика Return
мрачна; Они задокументированы в указанной вами ссылке. Вкратце, Return
выходит из самой внутренней конструкции (а именно, структуры управления или определения функции), в которой она вызывается.
Единственный случай, когда указанная выше функция CleanUp
не может очистить от Return
, - это когда вы непосредственно передаете один или CompoundExpression
(например, (one;two;three)
непосредственно в качестве входных данных для него.
Возврат из функции f
:
In[28]:= f[] := Return["ret"]
In[29]:= CleanUp[f[], Print["cleaned"]]
During evaluation of In[29]:= cleaned
Out[29]= "ret"
Return
выход x
:
In[31]:= x = Return["foo"]
In[32]:= CleanUp[x, Print["cleaned"]]
During evaluation of In[32]:= cleaned
Out[32]= "foo"
Return
выходит из цикла Do
:
In[33]:= g[] := (x = 0; Do[x++; Return["blah"], {10}]; x)
In[34]:= CleanUp[g[], Print["cleaned"]]
During evaluation of In[34]:= cleaned
Out[34]= 1
Возвращает из тела CleanUp
в точке, где оценивается body
(поскольку CleanUp
равно HoldAll
):
In[35]:= CleanUp[Return["ret"], Print["cleaned"]];
Out[35]= "ret"
In[36]:= CleanUp[(Print["before"]; Return["ret"]; Print["after"]),
Print["cleaned"]]
During evaluation of In[36]:= before
Out[36]= "ret"
Как я отмечал выше, последние два примера являются единственными проблемными случаями, которые я могу выдумать (хотя могу ошибаться), но их можно обработать, добавив определение к CleanUp
:
In[44]:= CleanUp[CompoundExpression[before___, Return[ret_], ___], form_] :=
(before; form; ret)
In[45]:= CleanUp[Return["ret"], Print["cleaned"]]
During evaluation of In[46]:= cleaned
Out[45]= "ret"
In[46]:= CleanUp[(Print["before"]; Return["ret"]; Print["after"]),
Print["cleaned"]]
During evaluation of In[46]:= before
During evaluation of In[46]:= cleaned
Out[46]= "ret"
Как вы сказали, не собираюсь выигрывать конкурсы красоты, но, надеюсь, это поможет решить вашу проблему!
Ответ на ваше обновление
Я бы сказал, что использование Return
внутри If
не является необходимым, и даже злоупотребление Return
, учитывая, что If
уже возвращает либо второй, либо третий аргумент в зависимости от состояния условия в первом аргумент. Хотя я понимаю, что ваш пример, вероятно, надуманен, If[3==3, Return["Foo"]]
функционально идентичен If[3==3, "foo"]
Если у вас есть более сложный оператор If
, вам лучше использовать Throw
и Catch
, чтобы выйти из оценки и «вернуть» что-то в точку, в которую вы хотите, чтобы оно было возвращено.
Тем не менее, я понимаю, что вы не всегда можете контролировать код, после которого нужно очистить, поэтому вы всегда можете заключить выражение в CleanUp
в неуправляемую структуру управления, например:
ret1 = Do[ret2 = expr, {1}]
... путем злоупотребления Do
для принудительного возврата Return
, не содержащегося в управляющей структуре в expr
, из цикла Do
. Единственная сложная часть (я думаю, что не попробовал это) - это иметь дело с двумя различными возвращаемыми значениями, указанными выше: ret1
будет содержать значение безусловного Return
, но ret2
будет иметь значение любой другой оценки expr
. Вероятно, есть более понятный способ справиться с этим, но сейчас я не вижу этого.
НТН!