Сделай сам себе язык

Nov 13, 2020 19:42

Для тех немногих сильных духом, кто заинтересовался «псевдо-макросами» в приложении к матмоделям, запилил статью с гораздо более подробными разъяснениями и всевозможной философией по этой теме.


Read more... )

наука, философия, xx2 век, программирование

Leave a comment

dobriy24 April 28 2023, 21:31:57 UTC
Крутая статья.
Правда у данного SmartModule есть одна проблема:
Он работает только когда завёрнут в какую-нибудь функцию, а когда он один в ячейке, то он не работает. Т.е., при вычислении f@SmartModule[x=2;x] получится f[2], а при вычислении SmartModule[x=2;x] получится не 2, а выражение SmartModule[x=2;x], т.к. у нашего SmartModule есть только UpValue. Но часто надо именно чисто считать SmartModule[...], если тебе не функцию надо определить, а просто посчитать кусок кода. Например, в данной статье (если не учитывать точку с запятой) тоже использовался "чистый" Block в конце программы. Можно всегда при таких ситуациях писать Activate@SmartModule[...], но это не круто.

Короче, чтобы избавиться от этой проблемы, я (на примере SmartModule) сделал так:
SmartModule[x_] /; !MemberQ[Stack[_], HoldForm[_[___, SmartModule[_], ___]]] :=
Activate@SmartModule[x];

Эта штука работает на функции Stack[_] - функция, которая показывает все выражения, которые надо вычислить при вызове Stack[_] (легче посмотреть документацию и примеры).
SmartModule будет сначала вызывать проверку !MemberQ[Stack[_], HoldForm[_[___, SmartModule[_], ___]]], а потом:
1) если это было ложью, то он пойдёт дальше и использует UpValue.
2) если это было правдой(т.е. если он не находится ни в какой функции), то вызовет Activate@SmartModule, после он снова вызовет проверку, проверка окажется ложью и он использует UpValue.

Очевидно, эта добавка к SmartModule не изменяет время работы функций типа f[z_]:=SmartModule[...]. Чисто теоретически, сами правила (OwnValue) для f[z] должны дольше считаться, но я ни на каких тестах этого не обнаружил. В целом, в моих тестах, SmartModule считает всё одинаково по времени хоть с этой добавкой, хоть без. Ещё Stack[_], говорят, достаточно "опасная" функция, так что я не уверен в коде.

Reply

lex_kravetski April 29 2023, 14:08:45 UTC
Более универсальным способом этот вопрос решается добавлением замены в $Pre. То есть не определять вообще никаких псевдо-функций, а вместо этого сделать замену по шаблону на этапе предобработки выражения. Но в этом случае почти весь код уже будет отличаться.

Reply

dobriy24 April 29 2023, 16:06:06 UTC
А, т.е., написать что-то типа
$Pre = Function[{ev},

ReplaceRepeated[Unevaluated@ev,
SmartModule[args_] :>
Module[Evaluate@Activate@extarctVars[Hold@args], args]],

HoldAll
]

Достаточно интересный метод. Правда в подобных прогах на wolfram очень сложно (по крайней мере для меня) не запутаться и не совершить ошибку в Hold, Evaluate, Activate и т.д.. А ведь иногда с этими функциями и ошибка сразу не видна и не очевидно как проверять.

Reply

lex_kravetski April 29 2023, 20:17:34 UTC
Ну, я для этих целей сделал специальную функцию, которая добавляет в $Pre, заблокировав в процессе добавления предобработку и предварительно проверяя, не добавлена ли уже такая функция. А потом Такие функции добавляю уже через эту. Поскольку, таки да, очень легко где-то что-то перепутать, а потому проще пользоваться однажды проверенной и отлаженной функцией добавления.

Private`PreReplacements = {};
Private`PreRepeatedReplacements = {};

Private`PreSetupMode = False;

Private`PreSetup = Function[
body,
Private`PreSetupMode = True;
body;
Private`PreSetupMode = False;,
HoldAll
];

$Pre = Function[code,
If[Private`PreSetupMode,
code,
Cases[code // Hold,
HoldPattern[
AddReplacementToPre[from_ :> _]] :> (Verbatim[from] :> _),
All
] //
Map[
(Private`PreReplacements =
DeleteCases[Private`PreReplacements, #]) &
];

Cases[code // Hold,
HoldPattern[
AddRepeatedReplacementToPre[
from_ :> _]] :> (Verbatim[from] :> _),
All
] //
Map[
(Private`PreRepeatedReplacements =
DeleteCases[Private`PreRepeatedReplacements, #]) &
];

Fold[
ReplaceEvaluated[#2][#1] &,
code // Hold,
Private`PreReplacements
] //

Fold[
ReplaceRepeated[#2][#1] &,
#,
Private`PreRepeatedReplacements
] & //
ReleaseHold
],
HoldAll
];

AddReplacementToPre = Function[
replacement,
AppendTo[Private`PreReplacements, replacement];
Private`PreReplacements,
HoldAll
];

AddRepeatedReplacementToPre = Function[
replacement,
AppendTo[Private`PreRepeatedReplacements, replacement];
Private`PreRepeatedReplacements,
HoldAll
];

Reply


Leave a comment

Up