开发者

picking specific symbol definitions in mathematica (not transformation rules)

开发者 https://www.devze.com 2023-03-30 08:15 出处:网络
I have a following problem. f[1]=1; f[2]=2; f[_]:=0; dvs = DownValues[f]; this gives dvs = { HoldPattern[f[1]] :> 1,

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 an开发者_运维技巧d gives someting strange, this excecution I certainly would like to avoid.


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


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.


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

Cases[DownValues[f], _?(FreeQ[#[[1]], Pattern | Blank] &)]
0

精彩评论

暂无评论...
验证码 换一张
取 消