То, что вы просите, сложно. Это работа для макросов, как уже показали другие. Я исследую другую возможность - использовать одни и те же символы, но поместите несколько оберток вокруг кода, который вы хотите написать. Преимущество этого метода заключается в том, что код преобразуется «лексически» и во время компиляции, а не во время выполнения (как в других ответах). Как правило, это быстрее и проще для отладки.
Итак, вот функция, которая преобразует With
с вашим предложенным синтаксисом:
Clear[expandWith];
expandWith[heldCode_Hold] :=
Module[{with},
heldCode /. With -> with //. {
HoldPattern[with[{{} = {}, rest___}, body_]] :>
with[{rest}, body],
HoldPattern[
with[{
Set[{var_Symbol, otherVars___Symbol}, {val_, otherVals___}], rest___},
body_]] :>
with[{{otherVars} = {otherVals}, var = val, rest}, body]
} /. with -> With]
Обратите внимание, что это работает с удерживаемым кодом. Преимущество этого в том, что нам не нужно беспокоиться о возможной оценке кода ни в начале, ни в конце expandWith
. Вот как это работает:
In[46]:= expandWith@Hold[With[{{x1,x2,x3}={a,b,c}},x+x1+x2+x3]]
Out[46]= Hold[With[{x3=c,x2=b,x1=a},x+x1+x2+x3]]
Это, однако, не очень удобно для использования. Вот удобная функция, чтобы упростить это:
ew = Function[code, ReleaseHold@expandWith@Hold@code, HoldAll]
Теперь мы можем использовать его как:
In[47]:= ew@With[{{x1,x2}={a,b}},x+x1+x2]
Out[47]= a+b+x
Итак, чтобы расширение произошло в коде, просто оберните ew
вокруг него. Вот ваш случай для определения функции:
Remove[f];
ew[f[x_] := With[{{x1, x2} = {a, b}}, x + x1 + x2]]
Теперь мы проверим и увидим, что мы получили расширенное определение:
?f
Global`f
f[x_]:=With[{x2=b,x1=a},x+x1+x2]
Преимущество этого подхода заключается в том, что вы можете обернуть ew
вокруг произвольно большого куска кода. Происходит следующее: сначала из него генерируется расширенный код, как если бы вы написали его самостоятельно, а затем этот код выполняется. В случае определений функций, таких как f
выше, мы можем сказать, что генерация кода происходит во время компиляции, поэтому вы избегаете любых накладных расходов во время выполнения при последующем использовании функции, которые могут быть существенными, если функция вызывается часто.
Еще одним преимуществом этого подхода является его сочетаемость: вы можете придумать множество расширений синтаксиса, и для каждого из них написать функцию, аналогичную ew
. Затем, при условии, что эти пользовательские функции преобразования кода не конфликтуют друг с другом, вы можете просто составить (вложить) их, чтобы получить кумулятивный эффект. В некотором смысле, таким образом, вы создаете собственный генератор кода, который генерирует действительный код Mathematica из некоторых выражений Mathematica, представляющих программы в вашем собственном языке, которые вы можете создавать в Mathematica, используя эти средства.
EDIT
При написании expandWith
я использовал итеративное применение правил, чтобы избежать контроля оценки, что может привести к путанице. Тем не менее, для тех, кто заинтересован, вот версия, которая делает некоторую явную работу с неоцененными частями кода.
Clear[expandWithAlt];
expandWithAlt[heldCode_Hold] :=
Module[{myHold},
SetAttributes[myHold, HoldAll];
heldCode //. HoldPattern[With[{Set[{vars__}, {vals__}]}, body_]] :>
With[{eval =
(Thread[Unevaluated[Hold[vars] = Hold[vals]], Hold] /.
Hold[decl___] :> myHold[With[{decl}, body]])},
eval /; True] //. myHold[x_] :> x]
Я считаю, что это намного сложнее, чем первый.