6

I have a following problem.

f[1]=1;
f[2]=2;
f[_]:=0;

dvs = DownValues[f];

this gives

dvs = 
   {
      HoldPattern[f[1]] :> 1, 
      HoldPattern[f[2]] :> 2, 
      HoldPattern[f[_]] :> 0
   }

My problem is that I would like to extract only definitions for f[1] and f[2] etc but not the general definition f[_], and I do not know how to do this.

I tried,

Cases[dvs, HoldPattern[ f[_Integer] :> _ ]] (*)

but it gives me nothing, i.e. the empty list.

Interestingly, changing HoldPattern into temporary^footnote

dvs1 = {temporary[1] :> 1, temporary[2] :> 2, temporary[_] :> 0}

and issuing

Cases[dvs1, HoldPattern[temporary[_Integer] :> _]] 

gives

{temporary[1] :> 1, temporary[2] :> 2}

and it works. This means that (*) is almost a solution.

I do not not understand why does it work with temporary and not with HoldPattern? How can I make it work directly with HoldPattern?

Of course, the question is what gets evaluated and what not etc. The ethernal problem when coding in Mathematica. Something for real gurus...

With best regards Zoran

footnote = I typed it by hand as replacement "/. HoldPattern -> temporary" actually executes the f[_]:=0 rule and gives someting strange, this excecution I certainly would like to avoid.

3 Answers3

7

The reason is that you have to escape the HoldPattern, perhaps with Verbatim:

In[11]:= Cases[dvs, 
            Verbatim[RuleDelayed][
               Verbatim[HoldPattern][HoldPattern[f[_Integer]]], _]]

Out[11]= {HoldPattern[f[1]] :> 1, HoldPattern[f[2]] :> 2}

There are just a few heads for which this is necessary, and HoldPattern is one of them, precisely because it is normally "invisible" to the pattern-matcher. For your temporary, or other heads, this wouldn't be necessary. Note by the way that the pattern f[_Integer] is wrapped in HoldPattern - this time HoldPattern is used for its direct purpose - to protect the pattern from evaluation. Note that RuleDelayed is also wrapped in Verbatim - this is in fact another common case for Verbatim - this is needed because Cases has a syntax involving a rule, and we do not want Cases to use this interpretation here. So, this is IMO an overall very good example to illustrate both HoldPattern and Verbatim. Note also that it is possible to achieve the goal entirely with HoldPattern, like so:

In[14]:= Cases[dvs,HoldPattern[HoldPattern[HoldPattern][f[_Integer]]:>_]]

Out[14]= {HoldPattern[f[1]]:>1,HoldPattern[f[2]]:>2}

However, using HoldPattern for escaping purposes (in place of Verbatim) is IMO conceptually wrong.

EDIT

To calrify a little the situation with Cases, here is a simple example where we use the syntax of Cases involving transformation rules. This extended syntax instructs Cases to not only find and collect matching pieces, but also transform them according to the rules, right after they were found, so the resulting list contains the transformed pieces.

In[29]:= ClearAll[a, b, c, d, e, f];
Cases[{a, b, c, d, e, f}, s_Symbol :> s^2]

Out[30]= {a^2, b^2, c^2, d^2, e^2, f^2}

But what if we need to find elements that are themselves rules? If we just try this:

In[33]:= Cases[{a:>b,c:>d,e:>f},s_Symbol:>_]
Out[33]= {}

It doesn't work since Cases interprets the rule in the second argument as an instruction to use extended syntax, find a symbol and replace it with _. Since it searches on level 1 by default, and symbols are on level 2 here, it finds nothing. Observe:

In[34]:= Cases[{a:>b,c:>d,e:>f},s_Symbol:>_,{2}]
Out[34]= {_,_,_,_,_,_}

In any case, this is not what we wanted. Therefore, we have to force Cases to consider the second argument as a plain pattern (simple, rather than extended, syntax). There are several ways to do that, but all of them "escape" RuleDelayed (or Rule) in some way:

In[37]:= Cases[{a:>b,c:>d,e:>f},(s_Symbol:>_):>s]
Out[37]= {a,c,e}

In[38]:= Cases[{a:>b,c:>d,e:>f},Verbatim[RuleDelayed][s_Symbol,_]:>s]
Out[38]= {a,c,e}

In[39]:= Cases[{a:>b,c:>d,e:>f},(Rule|RuleDelayed)[s_Symbol,_]:>s]
Out[39]= {a,c,e}

In all cases, we either avoid the extended syntax for Cases (last two examples), or manage to use it to our advantage (first case).

Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
  • Your solution is rather sophisticated and is open ended to pick almost anything from DownValues. I would really like to understand it more. I just have one more question. You tried to explain why Verbatim needs to wrap RuleDelayed, “this is needed because Cases has a syntax involving a rule, and we do not want Cases to use this interpretation here.” I fell this is something really important I would like to understand. Could you please explain this in a little bit more detail (provided you have the time and patience, of course). –  Aug 24 '11 at 08:01
  • Oh boy, how embarassing. I just checked Cases syntax in the Mathematica documentation and there is a way of invoking it like Cases[expr, pattern -> rhs]. What I really want is something like Cases[expr, "pattern -> rhs"]. Is this what you've meant? Oh, and another question: If I would use MatchQ instead of Cases then I would not need to worry about that particular issue since MatchQ requires strictly pattern. Is this correct? For example, then one could use MatchQ[expr, RuleDelayed[Verbatim[HoldPattern][HoldPattern[f[_Integer]]], _]]], right? –  Aug 24 '11 at 08:40
  • @zorank I added an explanation you requested, please see my edit. – Leonid Shifrin Aug 24 '11 at 08:48
  • @zorank Yes, you can do this, e.g. like this: `Cases[dvs, x_ /; MatchQ[Unevaluated@x, Verbatim[HoldPattern][HoldPattern[f[_Integer]]] :> _]]`. The problem with this approach is that it is easy to forget the `Unevaluated` part, which would lead to "evaluation leaks" - `Cases` would evaluate sub-parts during pattern - matching. Besides, this method might be less efficient, since it is not purely syntactic (`MatchQ` itself is based on syntax, but evaluator is still invoked by `Cases` to call it for every match candidate). I did not benchmark, though - the performance hit might be small here. – Leonid Shifrin Aug 24 '11 at 08:55
  • an interesting observation: MatchQ[HoldPattern[f[1]] :> 1, Verbatim[HoldPattern][f[_]] :> _] gives False. It should be true since there is no special syntax for MatchQ that allows pattern in the same sense as Cases does. –  Aug 24 '11 at 09:00
  • here I found something contradicting the disucussion so far regarding how Cases treats the second argument. An interesting observation I made by running MatchQ[HoldPattern[f[1]] :> 1, Verbatim[HoldPattern][f[_]] :> _] is that it gives False. It should be true since there is no special syntax for MatchQ that allows pattern in the same sense as Cases does. Why does it give False? I can't see what goes wrong. Especially, since MatchQ[a :> b, s_Symbol :> _] gives actually True. Please bear with me folks. –  Aug 24 '11 at 09:05
  • @zorank You should have used `MatchQ[HoldPattern[f[1]] :> 1, Verbatim[HoldPattern][HoldPattern[f[_]]] :> _]`. You forgot to wrap your `f` in `HoldPattern` inside your pattern, and it evaluated to something else before `MatchQ` could see it. – Leonid Shifrin Aug 24 '11 at 09:11
  • many thanks! actually f[_]:=0 kicks in so what is being sent to MatchQ as the second argument is `Verbatim[HoldPattern][0] :> _]`. By the way, is there any difference beetween `HoldPattern[f[_]:>_]` and `HoldPattern[f[_]]:>_`, and for that matter `HoldPattern[f][_]:>_`? –  Aug 24 '11 at 09:25
  • apparently the three forms of HoldPattern above are not equivalent. For exmaple `MatchQ[ HoldPattern[f[1]] :> 1, Verbatim[HoldPattern][ HoldPattern[f[_] :> _] ] ] ` gives False. Oh boy, I am really confused... –  Aug 24 '11 at 09:43
4

Leonid, of course, completely answered the question about why your temporary solution works but HoldPattern does not. However, as an answer to your original problem of extracting the f[1] and f[2] type terms, his code is a bit ugly. To solve just the problem of extracting these terms, I would just concentrate on the structure of the left-hand-side of the definition and use the fact that FreeQ searches at all levels. So, defining

f[1] = 1;  f[2] = 2;  f[_] := 0;
dvs = DownValues[f];

All of the following

Select[dvs, FreeQ[#, Verbatim[_]] &]
Select[dvs, FreeQ[#, Verbatim[f[_]]] &]
Select[dvs, ! FreeQ[#, HoldPattern[f[_Integer]]] &]

yield the result

{HoldPattern[f[1]] :> 1, HoldPattern[f[2]] :> 2}

Provided there are no f[...] (or, for the first version, Blank[]) terms on the right-hand-side of the downvalues of f, then one of the above will probably be suitable.

Simon
  • 14,631
  • 4
  • 41
  • 101
  • Many thanks Simon. If my understanding is correct this strategy eliminates unwanted cases. I am just curious, why would it not work with just the last line? The first two lines seem unecessary, but they probably guard from something. I am curious from what... –  Aug 24 '11 at 08:04
  • @zorank: Sorry for the confusion. All three lines yield the same result. You can choose which one you want. Although Mr Wizard's answer is cleaner and does basically the same thing. – Simon Aug 24 '11 at 09:55
  • 1
    @Simon My code may be ugly, but there is a reason:) It is 2-3 times faster than your versions for a large number of definitions, which is not accidental - my code is purely syntactic while yours invokes evaluator for every test in `Select`. This is not at all to detract from your solutions (in fact, I was tempted to post the one exactly matching your last one, but changed my mind, because strictly speaking you may get wrong results - if r.h.s. contains the pattern rather than l.h.s. - although this is an inlikely scenario). Besides, for small list of definitions the speed does not matter much. – Leonid Shifrin Aug 24 '11 at 20:01
3

Based on Simon's excellent solution here, I suggest:

Cases[DownValues[f], _?(FreeQ[#[[1]], Pattern | Blank] &)]
Community
  • 1
  • 1
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
  • +1 Using `Blank` is much better than `Verbatim[_]` (which is `Verbatim[Blank[]]`)! – Simon Aug 24 '11 at 07:44
  • That was fast and elegant. If my understanding is correct it picks cases where lhs of an expression does not contain any patterns. Just a question why one needs “Blank” also in the FreeQ call? Would that be hard to explain? I mean, isn't Blank a pattern? –  Aug 24 '11 at 08:02
  • 1
    @zorank, it is necessary to catch a case such as `f[_] := ` which has no named `Pattern` such as `f[x_] := `. `Blank` by itself may be enough, but it is surer to keep `Pattern` as well. ------- If you are thinking that `Blank` is the same as `_` it is not; the `FullForm` of `_` is actually `Blank[]`, and yes, that is different. – Mr.Wizard Aug 24 '11 at 08:08
  • @Mr.Wizard: many thanks. I am just curious, would having `__` or `___` in down values cause some problems, e.g. could such patterns be missed by FreeQ? –  Aug 24 '11 at 09:18
  • @zorank that is an excellent point. One would need to add `BlankSequence` and `BlankNullSequence` to pick up definitions that have those, but no named patterns in the left hand side. You could also have a definition like: `f[1 ..] :=` and you would need `Repeated` for that. All that makes this solution less elegant. Certainly it is easier to match *only* definitions for integers, but I wanted to give solution that works for other types as well. (`f["string"] :=`, `f[0, Pi]:=`, etc.) Ultimately I guess you have to decide whether an inclusive or exclusive filter makes more sense for you. – Mr.Wizard Aug 24 '11 at 09:42