11
$\begingroup$

I am reading Paul Wellin's "Essentials of Programming in Mathematica".

Mr. Wellin wrote the following in his book:

There is a convenient shorthand notation for conditional patterns that is commonly used. The condition expr_ /; test can be shortened to expr_?test.

But,

MatchQ[Range[10], {s__/;NumberQ[s]}]

returns an error and False. And,

MatchQ[Range[10], {s__?NumberQ}]

returns True.

Why?

$\endgroup$
14
$\begingroup$

__?test is not a shorthand for s__ /; test[s] in the sense that it is an alias. There are major differences that one needs to be aware of.

The third bullet point under "Details" in the documentation for PatternTest (?) is this:

In a form such as __?test, every element in the sequence matched by __ must yield True when test is applied.

MatchQ[Range[10], {s__ /; NumberQ[s]}] will evaluate

NumberQ[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

This will give an error (and return False) because NumberQ hasn't been defined to take that many arguments. You can fix it, in a sense, like this:

MatchQ[Range[10], {s__ /; NumberQ[{s}]}]

but now it returns False because NumberQ[{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}] sees a list, which is not a number.

To actually get what we want using this method, we have to do this:

MatchQ[Range[10], {s__ /; AllTrue[{s}, NumberQ]}]

__?test is much shorter for this type of test, but as we have seen it is not a shorthand in the sense that we can use it as a drop-in replacement wherever we want. ? essentially does the AllTrue[{s}, test] part for us.

$\endgroup$
  • 1
    $\begingroup$ Thank you very much, C. E. $\endgroup$ – tchappy ha Oct 18 '18 at 9:24
9
$\begingroup$

In short: you are confusing Blank[] (_) and BlankSequence[] (__). (There is also BlankNullSequence[] (___), but I shall skip talking about that to keep it short.)

What Wellin said about the patterns involving Blank[] (_) is mostly true, in that one has the choice of using Condition (/;) or PatternTest (?). So, you can do n_?NumberQ (the form often preferred for relatively simple expression tests) or n_ /; NumberQ[n] (more often used if the expression test is sufficiently complicated, e.g. n_ /; NumberQ[n] && Positive[n]). It is possible to express one in terms of the other, but the preferences I gave are common.

In your attempt, you were trying to use /; with BlankSequence[] (__); recall that __ is supposed to match one or more things, when the expression test NumberQ[] can only take one argument. So NumericQ[s] will choke if s was e.g. 1, 2, as you are now trying to give it two arguments.

In contrast, the pattern s__?NumberQ is fine; it is the way to test that s is one or more things that satisfy the expression test NumericQ[].

If you had really insisted on using /; for this, one way in this case is to use something like VectorQ[]:

MatchQ[Range[10], {s__} /; VectorQ[{s}, NumberQ]]
$\endgroup$
  • 1
    $\begingroup$ (I am writing from a smartphone, so please edit my answer if the formatting looks screwy on desktop.) $\endgroup$ – J. M. is away Oct 13 '18 at 10:31
  • $\begingroup$ Thank you very much, J. M. is computer-less. $\endgroup$ – tchappy ha Oct 18 '18 at 9:24

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.