0
$\begingroup$

I'm trying to write a function that accepts only a particular Head (for example, prints only Symbols) using pattern matching. However, the following code has me a bit of confused.

> printer[foo_] := Print[foo]
> printer[1]
1

This behaviour makes sense: the _ matches the Integer (1) and the printer works. Now I redefine the printer function:

> printer[foo_Symbol] := Print[foo]
> printer[1]
1

Now _Symbol should not match an Integer and I would expect printer[1] to be returned.

To make matters worse, if I'd done this in the opposite order, first defining printer[var_Symbol] then changing the definition to printer[var_], I get the expected result.

What's going on?

(Mathematica 10.0.1.0 on 64-bit Ubuntu 14.04)

$\endgroup$
2
  • 1
    $\begingroup$ Well, you have both definitions in context, and both definitions combine to mean, print anything, hence, the result you get. You'll have to clear printer first then redefine the second one only to get the behavior you want. $\endgroup$
    – RunnyKine
    Oct 14, 2014 at 3:24
  • $\begingroup$ Look at the result of ??foo. That will show you all the all the rules that are in force for evaluating foo. $\endgroup$
    – m_goldberg
    Oct 14, 2014 at 5:02

1 Answer 1

1
$\begingroup$

What is going on is pretty simple: Mathematica does not forget your first definition because the pattern is different. This makes sense! Assume you define the faculty

fac[0] = 1;
fac[n_] := fac[n - 1]*n

and your second definition line would overwrite the first one. Then, nothing would work because you would have killed the end of the recursion.

Your second part

To make matters worse, if I'd done this in the opposite order, first defining printer[var_Symbol] then changing the definition to printer[var_], I get the expected result.

is not true if you really did what you wrote. Let's define it the other way around:

ClearAll[printer]    
printer[foo_Symbol] := Print[foo]
printer[foo_] := Print[foo]

printer[1]
(* 1 *)

Here, too, the 1 is printed. This makes perfect sense because when you look at the rule attached to printer

DownValues[printer]
(* {HoldPattern[printer[foo_Symbol]] :> Print[foo], 
 HoldPattern[printer[foo_]] :> Print[foo]} *)

you see that both definitions are there. Since the first one with foo_Symbol doesn't match, Mathematica tries the next one which matches.

So if you want to make that printer[1] stays unevaluated, you cannot define a general rule which matches. Clear all definitions of printer and use the foo_Symbol definition only.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.