Skip to main content

conditional - Why does pattern test work only with pure functions?


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?



Answer



The 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.


Condition


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]]


PatternTest


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

The case at hand


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:



  • Your mistake was to supply an expression where a function was expected

  • Pattern name binding works in 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.


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...