Re: How to short-circuit match failure?

• To: mathgroup at smc.vnet.net
• Subject: [mg114255] Re: How to short-circuit match failure?
• From: Leonid Shifrin <lshifr at gmail.com>
• Date: Mon, 29 Nov 2010 06:06:23 -0500 (EST)

```Hi kj,

Here is one way:

In[105]:=

ClearAll[foo]
foo::toolong = "List is too long";
foo::nolist = "First argument is not a list";
foo::nargs = "foo called with `1` argument(s); 2 expected";
Module[{localfoo},
localfoo[x_List /; Length[x] < 3, y_] := {#, y} & /@ x;
localfoo[x_List, y_] :=
"" /; (Message[foo::toolong]; True) && Throw[\$Failed, localfoo];
localfoo[x_, y_] :=
"" /; (Message[foo::nolist]; True) && Throw[\$Failed, localfoo];
localfoo[x___] :=
"" /; (Message[foo::nargs, Length[{x}]]; True) &&
Throw[\$Failed, localfoo];
foo[args___] :=
Module[{result},
result = Catch[localfoo[args], localfoo];
result /; result =!= \$Failed]];

In[110]:= foo[{1,2,3},3]
During evaluation of In[110]:= foo::toolong: List is too long
Out[110]= foo[{1,2,3},3]

In[111]:= foo[1,3]
During evaluation of In[111]:= foo::nolist: First argument is not a list
Out[111]= foo[1,3]

In[112]:= foo[1,2,3]
During evaluation of In[112]:= foo::nargs: foo called with 3 argument(s); 2
expected
Out[112]= foo[1,2,3]

In[113]:= foo[{1, 2}, 3]

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

Note that by using the local variable <result>, shared between the body and
the condition,
I am able to ensure the standard semantics of function returning
unevaluated, when no
applicable rules are found. I don't see an easy way of achieving this
without this mechanism.

Hope this helps.

Regards,
Leonid

On Sun, Nov 28, 2010 at 2:52 PM, kj <no.email at please.post> wrote:

>
>
>
> When defining a function as a sequence of rules (with SetDelayed),
> I often want to have messages emitted if the arguments do not have
> the proper form, and then *stop* trying any remaining rules, but
> I don't know how to do the latter.
>
> Here's a silly example:
>
> ClearAll[foo]
> foo::toolong = "List is too long";
> foo::nolist = "First argument is not a list";
> foo::nargs = "foo called with `1` argument(s); 2 expected";
> foo[x_List /; Length[x] < 3, y_] := {#, y} & /@ x
> foo[x_List, y_] /; Message[foo::toolong] = Null
> foo[x_, y_] /; Message[foo::nolist] = Null
> foo[x___] /; Message[foo::nargs, Length[{x}]] = Null
>
> The function foo takes as its first argument a list with length no
> greater than 2.  But see what happens when foo[{1, 2, 3}, 3] is
> evaluated:
>
> In[86]:= foo[{1, 2, 3}, 3]
> During evaluation of In[86]:= foo::toolong: List is too long
> During evaluation of In[86]:= foo::nolist: First argument is not a list
> During evaluation of In[86]:= foo::nargs: foo called with 2 argument(s); 2
> expected
> Out[86]= foo[{1, 2, 3}, 3]
>
> The result in Out[86] is as desired, but spurious messages were
> emitted.  It's easy to see why.  During the evaluation of foo[{1,
> 2, 3}, 3], *all* the rules associated with foo are tried, even
> though the third and fourth ones should not be.
>
> I can prevent this from happening by letting the second rule's
> match succeed; e.g. by defining it like this:
>
> foo[x_List, y_] := (Message[foo::toolong]; Null)
>
> ...but now evaluating foo[{1, 2, 3}, 3] no longer produces the right
> final result (it produces Null, instead of foo[{1, 2, 3}, 3]).
>
> How can I define the second rule for foo so that the third and
> fourth ones are not tried, while the final value for foo[{1, 2,
> 3}, 3] remains as foo[{1, 2, 3}, 3]?
>
> TIA!
>
> ~kj
>
>
>

```

• Prev by Date: Re: How to short-circuit match failure?
• Next by Date: Re: Rendering transparent objects changed in M8
• Previous by thread: Re: How to short-circuit match failure?
• Next by thread: Re: How to short-circuit match failure?