Message Boards Message Boards

GROUPS:

[✓] Use Cases with RuleDelayed?

Posted 5 days ago
173 Views
|
6 Replies
|
7 Total Likes
|

Let us assume very simple and dumb example of pattern extracting from some data list by Cases[]:

Cases[{{1}, {2}}, x_ -> x[[1]]]

One can run it and get

During evaluation of In[1]:= Part::partd: Part specification x[[1]] is longer than depth of object.

Out[1]= {1, 2}

What a hell, why x is not an array?

Or a little more complex example:

In[287]:= Cases[{"2","1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"}, mList_String -> StringExtract[mList, All], 1]

During evaluation of In[287]:= StringExtract::strse: String or list of strings expected at position 1 in StringExtract[mList,All].

Out[287]= {{"2"},{"1", "0", "0", "0", "0", "1", "0", "0", "0", "0", "1", "0", "0", "0", "0", "1"}}

One can tell, that as we get after all an correct output there is no big problem in such warnings. But if we go a little deeper the real problem rises:

In[304]:= Cases[{"2", "1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"}, mList_String -> ToExpression[StringExtract[mList, All]], 1]

During evaluation of In[304]:= StringExtract::strse: String or list of strings expected at position 1 in StringExtract[mList,All].
During evaluation of In[304]:= ToExpression::notstrbox: StringExtract[mList,All] is not a string or a box. ToExpression can only interpret strings or boxes as Wolfram Language input.

Out[304]= {$Failed, $Failed}

Any correct result at all. 

So, what is exact problem with Cases[] and how to fix it correctly (i managed to make a simple and dirty fix, but do not like it)?

6 Replies
Posted 5 days ago

You are supposed to be using RuleDelayed (:>) and not Rule (->) in a situation where you don't want the right-hand side to evaluate at once:

Cases[{{1}, {2}}, x_ :> x[[1]]]
   {1, 2}

Cases[{"2", "1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"}, 
      mList_String :> ToExpression[StringExtract[mList, All]], 1]
   {{2}, {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}}

FWIW, it is a little unfair to label as a "bug" a situation where the inappropriate function was used.

POSTED BY: J. M.
Answer

You are supposed to be using RuleDelayed (:>) and not Rule (->)

Thank you. It works. Documentation gives a little examples of RuleDelayed and any explication of differences, most exmaples contains Rule. I think it needed to be in "Possible Issuses" section.

in a situation where you don't want the right-hand side to evaluate at once:

Err, in fact I do not "want". I forced to use this or that semantics and I'm not shure how to distinguish them. So, the real root of problem is that Rule[] try to evaluate the rightest part "when it is first entered", before substitution of exact values. Maybe in try to save a little time & mem by reducing the expression? Rarely it will succeed. Often it is not problem and everyone closes eyes on failure:

In[6]:= 1. /. x_Real -> Sin[ArcTan[x]]
Out[6]= 0.707107

Sometimes it fails and throw exceptions:

In[7]:= "1 2. 3 4.0" /. x_String -> StringExtract[x, All]
During evaluation of In[7]:= StringExtract::strse: String or list of strings expected at position 1 in StringExtract[x,All].
Out[7]= {"1", "2.", "3", "4.0"}

A = {1, 2, 3}
In[8]:= A /. x_ -> x[[2]]
During evaluation of In[8]:= Part::partd: Part specification x[[2]] is longer than depth of object.
During evaluation of In[8]:= Part::partd: Part specification A[[2]] is longer than depth of object.
Out[8]= A[[2]]

And sometimes it will give weird, unexpected result without warning:

In[10]:= 1. /. x_Real -> ToString[ArcTan[x]]
Out[10]= "ArcTan[x]"

So, we can assume that Rule[] is obsolete - haven't any unique functionality and tends to mistakes, and one will always use RuleDelayed[] unstead? Or there is some unexpected caveats?

FWIW, it is a little unfair to label as a "bug" a situation where the inappropriate function was used.

Oh, I have noticed that someone already changed the title of my previous question, so that is not a problem at all there.

Snegirev,

I think that your discussion of Rule and RuleDelayed in response to J.M. is not accurate. You should read this section about the Evaluation sequence in Mathematica. You should also become more familiar with Rule (->), RuleDelayed (:>), Set(=), and SetDelayed (:=). As a brief overview, Most MMA functions evaluate their arguments as completely as possible unless they have the "Hold" Attribute. Cases and Rule are normal functions with no Hold Attributes. What this means is that Cases will completely evaluate all of its arguments including the right hand side of the rule BEFORE it is ever applied.

For example,

In[1]:= x = 5;
Cases[{1, 2, 3}, x_ -> f[x]]

Out[1]= {f[5], f[5], f[5]}

In this case, even though x will eventually be replaced as a pattern, The right hand side of the Rule evaluates completely, replacing the "x" with its global value and the Rule becomes

x->f[5]

Which may not be what was intended. RuleDelayed is a way to stop the normal evaluation and hold the "f[x]" until the rule is applied:

In[2]:= x = 5;
Cases[{1, 2, 3}, x_ :> f[x]]

Out[2]= {f[1], f[2], f[3]}

The reason your Sin[ArcTan[x]] works with Rule is that it gets completely evaluated as a legitimate expression, however, x[[1]] is not a legitimate expression because x is a symbol and Part cannot operate on any Atomic expression (AtomQ[x] is True). In this case you must force the Rule to not evaluate your expression until the rule is applied (and x is substituted) by using RuleDelayed.

Neither Rule or RuleDelayed is obsolete. They each have their uses. The same is true of Set and SetDelayed. In both cases most of the time they will have the same result but in certain situations you must choose one or the other to get the behavior that you want. Sometimes you must have evaluation first before the Rule or the Set, in other cases (as you discovered) you must not have evaluation first.

I hope this helps,

Regards,

Neil

My point is that similar explanation must be in "Possible issues" section of Rule[] doc page. But today such section is absent at all. And maybe some references in Cases[] and similar derived stuff too.

Because of Cases[] and others applications tell about "patterns":

Cases[{Subscript[e, 1],\[Ellipsis]},pattern->rhs]
gives a list of the values of rhs corresponding to the Subscript[e, i] that match the pattern. 

Patterns are not self-essential, it must be applied to something before calculations. By principal goal it need to be a deferred calculation.

But Wolfram Kernel takes the different point. It's not a real bug, it is peculiarity, but it tends to disambiguation and potential errors.

Because of documentation "clearly" instruct us

Find the sum of every pair of elements:
In[2]:= Cases[{{1, 2}, {2}, {3, 4, 1}, {5, 4}, {3, 3}}, {a_, b_} -> a + b]
Out[2]= {3, 9, 6}

But tells nothing about that if one have already put somewhere deep in code a simple definition like

a = 100;

you'll surprisingly got

In[6]:= Cases[{{1, 2}, {2}, {3, 4, 1}, {5, 4}, {3, 3}}, {a_, b_} -> 
  a + b]
Out[6]= {102, 104, 103}

instead.

That's the point.

In both cases most of the time they will have the same result but in certain situations you must choose one or the other to get the behavior that you want.

Can you please give me an example of such pattern substitution where the use of the immediate Rule[] is essential? Maybe the documentation need to be changed for usage :> in most cases and only in rare occasions -> need to be used?

Can you please give me an example of such pattern substitution where the use of the immediate Rule[] is essential? Maybe the documentation need to be changed for usage :> in most cases and only in rare occasions -> need to be used?

Sometimes you must have immediate evaluation to get the token that you are pattern matching. Let's say you are evaluating an expression that has x in it, you want to make a rule with x-- the only way to do that is to use immediate evaluation. Below, "express" would be the result of some other calculations that has variable "x" in it.

In[1]:= express = f[x]

Out[1]= f[x]

In[2]:= Cases[{1, 2, 3}, x_ -> express]

Out[2]= {f[1], f[2], f[3]}

In[3]:= Cases[{1, 2, 3}, x_ :> express]

Out[3]= {f[x], f[x], f[x]}

In this case, the RuleDelayed gives the "wrong" answer for what was intended. Rule would be correct here.

My point is that similar explanation must be in "Possible issues" section of Rule[] doc page. But today such section is absent at all. And maybe some references in Cases[] and similar derived stuff too.

That is a good suggestion. You should contact support (and point them to this thread). I have made similar documentation suggestions in the past and they have been very responsive. The link is here for technical support.

Regards,

Neil

The difference between Rule and RuleDelayed is explained under Properties & Relations.

Every online documentation page has a Feedback link at the bottom. You can suggest improvements there.

https://reference.wolfram.com/language/ref/Rule.html

Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract