Может быть, я наивен, но, на мой взгляд, ваши определения - хорошее начало. Такие вещи, как g > 0->True
могут быть добавлены через UpValues
. Чтобы Positive[g^2]
вернул True
, вам, вероятно, придется перегрузить Positive
из-за ограничения глубины 1 для UpValues
. Вообще, я думаю, что точный набор автоматически вычисляемых выражений, включающих константу, является движущейся целью даже для встроенных констант. Другими словами, эти дополнительные встроенные правила, по-видимому, определяются из удобства и частого использования в каждом конкретном случае, а не из первых принципов. Я бы просто добавил новые правила по мере необходимости, когда вы чувствуете, что они вам нужны. Вероятно, вы не можете ожидать, что ваши константы будут так же хорошо интегрированы в систему, как встроенные, но я думаю, что вы можете быть довольно близки. Возможно, вам придется перегружать ряд встроенных функций для этих символов, но опять же, какие из них будут зависеть от того, что вам нужно от вашего символа.
EDIT
Я не решался включить это, поскольку приведенный ниже код является хаком, но может быть полезным в некоторых обстоятельствах. Вот код:
Clear[evalFunction];
evalFunction[fun_Symbol, HoldComplete[sym_Symbol]] := False;
Clear[defineAutoNValue];
defineAutoNValue[s_Symbol] :=
Module[{inSUpValue},
s /: expr : f_[left___, s, right___] :=
Block[{inSUpValue = True},
With[{stack = Stack[_]},
If[
expr === Unevaluated[expr] &&
(evalFunction[f, HoldComplete[s]] ||
MemberQ[
stack,
HoldForm[(op_Symbol /; evalFunction[op, HoldComplete[s]])
[___, x_ /; ! FreeQ[Unevaluated[x], HoldPattern@expr], ___]],
Infinity
]
),
f[left, N[s], right],
(* else *)
expr
]]] /; ! TrueQ[inSUpValue]];
ClearAll[substituteNumeric];
SetAttributes[substituteNumeric, HoldFirst];
substituteNumeric[code_, rules : {(_Symbol :> {__Symbol}) ..}] :=
Internal`InheritedBlock[{evalFunction},
MapThread[
Map[Function[f, evalFunction[f, HoldComplete[#]] = True], #2] &,
Transpose[List @@@ rules]
];
code]
При этом вы можете разрешить символу автоматически подставлять его числовое значение в тех местах, где мы указываем, что некоторые функции, связанные с этими вызовами функций, могут извлечь из этого пользу. Вот пример:
ClearAll[g, f];
SetAttributes[g, Constant];
N[g] = 9.81;
NumericQ[g] ^= True;
defineAutoNValue[g];
f[g] := "Do something with g";
Здесь мы попытаемся вычислить некоторые выражения, включающие g
, сначала обычно:
In[391]:= {f[g],g^2,g^2>0, 2 g, Positive[2 g+1],Positive[2g-a],g^2+a^2,g^2+a^2>0,g<0,g^2+a^2<0}
Out[391]= {Do something with g,g^2,g^2>0,2 g,Positive[1+2 g],
Positive[-a+2 g],a^2+g^2,a^2+g^2>0,g<0,a^2+g^2<0}
А теперь внутри нашей обертки (второй аргумент дает список правил, чтобы указать, для каких символов какие функции, когда оборачиваются вокруг кода, содержащего эти символы, должны приводить к замене этих символов их числовыми значениями):
In[392]:=
substituteNumeric[{f[g],g^2,g^2>0, 2 g, Positive[2 g+1],Positive[2g-a],g^2+a^2,g^2+a^2>0,
g<0,g^2+a^2<0},
{g:>{Positive,Negative,Greater}}]
Out[392]= {Do something with g,g^2,True,2 g,True,Positive[19.62\[VeryThinSpace]-a],
a^2+g^2,96.2361\[VeryThinSpace]+a^2>0,g<0,a^2+g^2<0}
Поскольку вышеизложенное является хаком, я не могу ничего гарантировать по этому поводу. В некоторых случаях это может быть полезно, но это должно решаться в каждом конкретном случае.