# NumericQ exercise in Wagner

• I think there are a few missing pieces in the problem description. NumberQ[π], for instance, returns False. That means you have to check for a different attribute (hint, hint ;)). Commented Aug 14, 2016 at 16:12
• I need to read that book more carefully! I just learned something really surprising to me: invalid syntax is NumericQ. NumericQ@Mod[1, 2, 3, 4, 5] yields True. Thanks for asking this! Commented Aug 14, 2016 at 16:12
• @Mr. Wizard, to give another pathology of NumericQ[]: it gives a True result for QPochhammer[2] even if that does not actually evaluate to a number with N[]. Commented Aug 14, 2016 at 16:21
• @J.M. My eye have been opened. Good thing I do not write production code or I would have a lot of leaks to fix in my argument testing. One I was aware of is that _Symbol will match Symbol[foo, bar], _Real will match Real[1,2,3] etc. Do any others common ones come to mind? (I foolishly thought the Q tests were more robust.) Commented Aug 14, 2016 at 16:25
• @Mr. Wizard, that prolly should be a separate question… :) Commented Aug 14, 2016 at 16:27

Here is a first attempt at implementing this, likely not robust.

SetAttributes[{attrQ, numberQ}, HoldAll];

attrQ[s_Symbol, attr_] := MemberQ[Attributes @ s, attr]

numberQ[x_] := NumberQ @ Unevaluated @ x || attrQ[x, Constant]

numericQ[expr_] :=
Replace[
Hold[expr],
_?numberQ | h_[__?numberQ] /; attrQ[h, NumericFunction] :> 1,
{1, -1}
] === Hold[1]


It matches the (surprising to me) behavior of NumericQ on:

numericQ[Mod[1, 2, 3, 4] + Pi^2]


Mod::argt: Mod called with 4 arguments; 2 or 3 arguments are expected. >>

True


Replace is used for a bottom-up collapse of the tree; for another example see:

Here is a second attempt, this time using recursion, and not attempting to avoid evaluation of the elements to allow for cleaner code.

ClearAll[attrQ, numericQ]

Attributes[attrQ] = HoldAll;

attrQ[s_Symbol, attr_] := MemberQ[Attributes@s, attr]

numericQ[_?NumberQ] = True;
numericQ[s_ /; attrQ[s, Constant]] = True;
numericQ[h_[___?numericQ] /; attrQ[h, NumericFunction]] = True;
numericQ[_] = False;


Tests:

numericQ[E^(I Pi)]
numericQ[Mod[1, 2, 3, 4] + Pi^2]
numericQ[1 + 2^"x" + Pi^2]
numericQ[7 + foo[1, 2, Pi^2]]

True


Mod::argt: Mod called with 4 arguments; 2 or 3 arguments are expected. >>

True

False

False

• Interesting, yet Wagner asks about recursive implementation ... Can we agree that's one weird exercise.
– BoLe
Commented Aug 14, 2016 at 18:28
• @BoLe Oh, let me think about that. Commented Aug 14, 2016 at 21:35
• @BoLe, I suppose something along the lines of recursively checking attrQ[head, NumericFunction] until you hit an atom where numberQ[] can be applied as the base case. Commented Aug 14, 2016 at 22:00
• I think this is it; ___?numericQ, nice ...
– BoLe
Commented Aug 15, 2016 at 12:03