9
$\begingroup$

Suppose you run into a bewildering Mathematica result (which happens to me several times per Mathematica session, even after a 20-year acquaintance), such as, for example:

MatchQ[42, _?Function[x, True]]
False

So you go pore over the docs, but you still can't figure out an explanation. Then what?

What tool can one use to figure out why Mathematica's evaluation is different from what one expects?

PS. By sheer luck, I had read something a few days earlier that helped me figure out the answer to the one above, but I would have never guessed it without that prior hint. Yes, after knowing the answer I can zero in the place in the docs where the mystery is solved, but only then. This is why the documentation does not go as far in such situations as one would think: if one knew where in the documentation to look, one wouldn't have been puzzled by the original result in the first place. Here's a different hint: when completely nonplussed, what could be more fitting than to interrogate the documentation for ?

$\endgroup$
10
  • $\begingroup$ I gave my answer to this question here: mathematica.stackexchange.com/a/3146/121 $\endgroup$
    – Mr.Wizard
    Oct 3, 2012 at 14:07
  • $\begingroup$ I feel like the obvious answer is: This site. However I'm sure you are looking for a different answer. $\endgroup$
    – jVincent
    Oct 3, 2012 at 14:08
  • 2
    $\begingroup$ Checking the full form of the expression is a good thing to check. MatchQ[42, _?Function[x, True]] // FullForm // HoldForm. A trace such as Trace[MatchQ[42, _?Function[x, True]], TraceOriginal -> True] would have shown the problem too $\endgroup$
    – Rojo
    Oct 3, 2012 at 14:13
  • 2
    $\begingroup$ Related: mathematica.stackexchange.com/q/1699/5 $\endgroup$
    – rm -rf
    Oct 3, 2012 at 14:19
  • 2
    $\begingroup$ @LeonidShifrin The problem is an exact dupe, but my understanding of the question is that it was only used as an illustration and the OP wanted to know how he could've gone about finding the error $\endgroup$
    – rm -rf
    Oct 3, 2012 at 14:24

3 Answers 3

13
$\begingroup$

My first instinct in such cases is usually to use Trace to figure out which part of the evaluation is behaving differently from what I expect. For the example you already have this point isolated. Then I typically try to dissect it and determine why it misbehaves. An important part of this dissection is using FullForm to remove all the shorthands that are sometimes interpreted differently then you expect due to precedence rules. Which is also the case here for this problem.

 MatchQ[42, _?Function[x, True]] // Trace
 {MatchQ[42,_?Function[x,True]],False}

This just shows us that we have already pinpointed the point of interest.

 MatchQ[42, _?Function[x, True]] // HoldComplete // FullForm
HoldComplete[MatchQ[42,PatternTest[Blank[],Function][x,True]]]

Here we can easily see that the problem is that the PatternTest (_?Function[x, True]) is bound differently then we expect, actually being interpreted as ((_?Function)[x, True]) Thus the solution is to insert proper grouping.

 MatchQ[42, _?(Function[x, True])]
True

Update

While writing this answer, I realised that my little mental exercise of putting in "invisible" parenthesis could be automated, and wrote a quick function for doing just that.

 SetAttributes[parenthesis, HoldAll]
 MakeBoxes[parenthesis[exp_], StandardForm] ^:= RowBox[{"(", MakeBoxes@exp, ")"}]

SetAttributes[Parenthesise, HoldAll]
 Parenthesise[expression_] := 
 HoldComplete[expression] //. 
  f_[pre___, arg_, post___] /; ! (f === parenthesis) && ! (Head@arg === parenthesis) :> 
     f[pre, parenthesis[arg], post] // Defer @@ # &

Which allows one to call:

 Parenthesise[MatchQ[42, _?Function[x, True]]]
 Parenthesise[MatchQ[42, _?(Function[x, True])]]
     (MatchQ[(42), ((_)?(Function)[(x), (True)])])
     (MatchQ[(42), ((_)?(Function[(x), (True)]))])

A better such function could most definitely be created, but I thought it was worth sharing.

$\endgroup$
3
  • $\begingroup$ I see we are thinking alike. FWIW you may find the FullForm variation I show of interest. $\endgroup$
    – Mr.Wizard
    Oct 3, 2012 at 14:18
  • $\begingroup$ Hey, @Mr.Wizard don't leave me out of the alike-thinking club, I was first in the comment. Humpf $\endgroup$
    – Rojo
    Oct 3, 2012 at 14:24
  • $\begingroup$ @Rojo sorry, I was writing my answer at that point. $\endgroup$
    – Mr.Wizard
    Oct 3, 2012 at 14:26
10
$\begingroup$

I gave my answer to this question here: https://mathematica.stackexchange.com/a/3146/121

Let me show how those recommendations apply to this specific problem.

1. Expanding the selection with Ctrl+.

Using Ctrl+. on a few parts would quickly show something like this:

Mathematica graphics

This would alert you that something strange is going on.

2. Displaying the expression with FullForm and TreeForm

Looking at the held FullForm:

MatchQ[42, _?Function[x, True]] // FullForm // HoldForm
MatchQ[42, PatternTest[Blank[], Function][x, True]]

We can see the precise way in which Mathematica is interpreting this expression.

We could also use TreeForm. (Unevaluated is needed to handle an evaluation leak in TreeForm):

MatchQ[42, _?Function[x, True]] // Unevaluated // Unevaluated // TreeForm

Mathematica graphics

$\endgroup$
3
  • 2
    $\begingroup$ FullForm is always my first choice, well after banging my head for a bit. But, a thought just occurred to me: combining it with Leonid's syntax highlighter would a good solution into an excellent one. It would remove some of the pitfalls of trying to manually parse the expression returned by FullForm. I think TreeForm is a good start in that process, but I find it more difficult to understand, i.e. I don't process it as quickly. $\endgroup$
    – rcollyer
    Oct 3, 2012 at 14:25
  • $\begingroup$ @rcollyer You pointed at code formatter, not syntax highlighter:-). Which one did you mean, probably the formatter? $\endgroup$ Oct 3, 2012 at 14:52
  • $\begingroup$ @LeonidShifrin likely the latter, but it does highlighting too, correct? Although on further reading, I'm not sure it does. But, either would work. Anything to decrease the visual density of the output from FullForm is welcome. If the syntax highlighter can be hooked in, too, even better. $\endgroup$
    – rcollyer
    Oct 3, 2012 at 15:24
4
$\begingroup$

Perhaps something along the lines of this helps visualize the FullForm, and would have made you realise that _?Function was being interpreted as a head of (_?Function)[x, True]

SetAttributes[f, HoldFirst];
f[h_[args___]] := OpenerView[{HoldForm@Panel@h, Column[f /@ Unevaluated /@ {args}]}];
f[sth_] := HoldForm@sth;

f@MatchQ[42, _?Function[x, True]]

In any case, Ctrl+. or mouse clicking seems to me the most useful tool to check precedence. When you really want to know what's going on and have narrowed down your problem to a small line of code, a trace has all you need. In this case,

Trace[MatchQ[42, _?Function[x, True]], TraceOriginal -> True]

would show the problem in its output

$\endgroup$

Your Answer

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

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