На самом деле, функция ValueQ не является невинной, поскольку она пропускает оценку для кода с побочными эффектами. Примеры:
ClearAll[f, g];
f[x_] := Print[x];
g[x_][0] := Print[x];
{ValueQ[f[1]],ValueQ[g[2][0]]}
Если вы удалите атрибут ReadProtected из ValueQ и посмотрите на код, вы поймете, почему - код очень прост и выполняет достойную работу только для OwnValues. Вот более сложная версия, которую я разработал, чтобы избежать этой проблемы (вы можете проверить, что, по крайней мере для приведенных выше примеров, она не дает утечки):
ClearAll[symbolicHead];
SetAttributes[symbolicHead, HoldAllComplete];
symbolicHead[f_Symbol[___]] := f;
symbolicHead[f_[___]] := symbolicHead[f];
symbolicHead[f_] := Head[Unevaluated[f]];
ClearAll[partialEval];
SetAttributes[partialEval, HoldAllComplete];
partialEval[a_Symbol] /; OwnValues[a] =!= {} :=
Unevaluated[partialEval[a]] /. OwnValues[a];
partialEval[a : f_Symbol[___]] /; DownValues[f] =!= {} :=
With[{dv = DownValues[f]},
With[{eval = Hold[partialEval[a]] /. dv},
ReleaseHold[eval] /;
(First[Extract[eval, {{1, 1}}, HoldComplete]] =!=
HoldComplete[a])]];
partialEval[a_] :=
With[{sub = SubValues[Evaluate[symbolicHead[a]]]},
With[{eval = Hold[partialEval[a]] /. sub},
ReleaseHold[eval] /;
(First[Extract[eval, {{1, 1}}, HoldComplete]] =!=
HoldComplete[a])]];
ClearAll[valueQ];
SetAttributes[valueQ, HoldAllComplete];
valueQ[expr_] := partialEval[expr] =!= Unevaluated[partialEval[expr]];
Это также не полный процесс, поскольку он не учитывает значения UpValues, NValues и FormatValues, но этого, по-видимому, достаточно для ваших заявленных потребностей, а также, возможно, правила для этих трех дополнительных случаев также могут быть добавлены к тому же самому линии, как указано выше.