6
$\begingroup$

I've been thinking about this exercise in Wagner (p. 269), but I can't answer. Can you tell me?

enter image description here

$\endgroup$
  • 1
    $\begingroup$ 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 ;)). $\endgroup$ – J. M. will be back soon Aug 14 '16 at 16:12
  • 1
    $\begingroup$ 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! $\endgroup$ – Mr.Wizard Aug 14 '16 at 16:12
  • 1
    $\begingroup$ @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[]. $\endgroup$ – J. M. will be back soon Aug 14 '16 at 16:21
  • $\begingroup$ @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.) $\endgroup$ – Mr.Wizard Aug 14 '16 at 16:25
  • $\begingroup$ @Mr. Wizard, that prolly should be a separate question… :) $\endgroup$ – J. M. will be back soon Aug 14 '16 at 16:27
4
$\begingroup$

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
$\endgroup$
  • $\begingroup$ Interesting, yet Wagner asks about recursive implementation ... Can we agree that's one weird exercise. $\endgroup$ – BoLe Aug 14 '16 at 18:28
  • $\begingroup$ @BoLe Oh, let me think about that. $\endgroup$ – Mr.Wizard Aug 14 '16 at 21:35
  • 1
    $\begingroup$ @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. $\endgroup$ – J. M. will be back soon Aug 14 '16 at 22:00
  • $\begingroup$ I think this is it; ___?numericQ, nice ... $\endgroup$ – BoLe Aug 15 '16 at 12:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.