Why is it that pattern test works only with pure functions?
Cases[Range[0, 70], _?(Divisible[#, 7] &)]
Cases[Range[0, 70], x_?(Divisible[x, 7])]
I understand that in the second case /;
should be used but why does ?
fail in technical sense?
Mathematica Stack Exchange is a question and answer site for users of Wolfram Mathematica. It only takes a minute to sign up.
Sign up to join this communityThe two ways of attaching a test to a pattern, Condition
and PatternTest
, have fundamentally different semantics. Your mistake was that you tried to use the semantics of Condition
in PatternTest
.
When you test with condition, you can attach a name to a pattern, and use that name also in the code in the second argument in Condition
- and that name will be bound to the name of the pattern - this is how Condition
works:
Cases[Range[0, 70], x_/;Divisible[x, 7]]
This is a general construct, so you can use it also with several pattern variables:
Cases[Partition[Range[10],2,1], {x_,y_} /; x > 3 && OddQ[y]]
With PatternTest
(?
), the situation is different.
First, PatternTest
expects a function as a second argument, not an expression. What this means is that, given a pattern
_?f
The test in say Cases[{1,2,3}, _?f]
will be performed as f[1]
, f[2]
, f[3]
. If the result evaluates to True
, the pattern-matcher considers the element to match the pattern. For any other outcome, pattern-matcher considers the element to not match the pattern.
Second, for PatternTest
it makes no sense to name the pattern. If you use
x_?f
then there is no way you can use x
inside f
, this binding is ignored by f
, simply because f
is considered a function that is anyway applied to the matched element. The only reason to name patterns used with PatternTest
is to use these names on the r.h.s. of the rule, for example:
fun[x_?f]:= x^2
or, may be, when you want to apply further conditions in some other places:
fun[x_?f, y_?f] /; x > y := Null
In your case, using
Cases[Range[0, 70], x_?(Divisible[x, 7])]
means that the tests will form "function calls" of the form
Divisible[x,7][elem]
where elem
is one of 1, 2 ,..., 70
, and since these won't evaluate further (e.g. Divisible[x,7][10]
), the pattern-matcher considers the elements to not match the pattern. Note that x
in the above will not be bound to x
in the pattern x_
, as I explained above - rather, it will be a symbol taken from the surrounding environment, and its presence wouldn't make much sense.
As you noted in comment, the way to make this work (one of them), is then to define
f[x_] := Divisible[x, 7]
and then use it as
Cases[Range[0, 70], _?f]
In this case, f
has semantics of a function, and binding between x
in x_
and x
in Divisible[x, 7]
is provided by SetDelayed
.
In any case, the bottom line is that:
Condition
, which expects an expression as a second argument, but not for PatternTest
, which expects a function as a second argument, and for which therefore such a binding makes no sense.
10
, you apply a test of the formDivisible[x, 7][10]
, withx
not being bound to anything (or, being bound to some global value, ifx
had a global value). It just doesn't make sense.PatternTest
expects a function, that would take your agrument and evaluate toTrue
orFalse
(with anything else thanTrue
interpreted by a pattern-matcher asFalse
), while you provide to it some expression, which doesn't behave like a function. $\endgroup$f[x_] := Divisible[x, 7]; Cases[Range[0, 70], _?f]
. Thanks. $\endgroup$