Probably this question has no application but it helps understand basic issues about Attributes and functions.

I was writing a piece of code where I accidently defined a function like this:

SetAttributes[f1, HoldAll]
f1[list_List] := "evaluated"

When evaluated I get results as expected:

f1[{1, 2}]

But when I tried to check if this works with Pattern test I was surprised that evaluation happened in the function argument:

SetAttributes[f2, HoldAll]
f2[list_?(Head[#] == List &)] := "evaluated"
f2[{1, 2}]

Same result with Pattern Condition /;

My question is that what kind of behavior is this and why does not HoldAll hold the argument (which I understand is anything inside the brackets [] of the function) from evaluation and is this behavior same for all other Attributes?

Thank you.

  • 3
    $\begingroup$ FYI this is discussed in the Possible Issues section of the PatternTest documentation $\endgroup$ Commented Dec 29, 2015 at 22:38
  • $\begingroup$ @SimonWoods Good to know, thanks. I wasn't aware that this has been discussed in the docs. $\endgroup$ Commented Dec 29, 2015 at 22:52

1 Answer 1


General explanation

The semantics of PatternTest and Condition is that the main evaluator is called to test the pattern, when those are used. It is called internally by the pattern-matcher, and this call is independent from the main evaluation procedure for the main expression. The reason is that the evaluations used to determine the pattern match should be considered sub-evaluations, rather than a part of the standard evaluation procedure for the main expression being evaluated.

This means that Hold* - attributes don't prevent evaluation requested by the pattern-matcher to test the fact of the match. This is one reason why one has to be careful when using such tests, to avoid evaluation leaks introduced through Condition and PatternTest via the pattern-matcher. In particular, you may want to use the construct like

f2[list_?(Function[Null, Head[Unevaluated @ #] == List, HoldAll])] := "evaluated"

to make it roughly equivalent to the first pattern you considered.

Relevant Links

  • Apparently, as noted by Simon Woods in comments, this issue is discussed in the Possible issues section of the PatternTest documentation page
  • A related discussion in a very similar context can be found here
  • I have considered a similar situation also in this answer.
  • $\begingroup$ Clear but one more thing to make it fully clear. if the function is defined like this: f2[list_List?(Head[#] == List &)] := "evaluated" then no evaluation happened and the PatternTest is not able to call the evaluator . $\endgroup$ Commented Dec 29, 2015 at 22:32
  • $\begingroup$ @Algohi Yes, because _List acts as a prefiltering device. This means that the pattern-matcher stops at that point and does not need to call the test function, because it rejects the pattern at an earlier stage of _List. $\endgroup$ Commented Dec 29, 2015 at 22:36
  • $\begingroup$ Aha, it is like that the checking of the argument starts and proceed sequentially. If one pattern/condition passed than proceed to the next. $\endgroup$ Commented Dec 29, 2015 at 22:38
  • $\begingroup$ @Algohi I'd rather say that for patterns of the type p_head /; test[p] or p_head?test, the procedure to match the pattern is that first, the p_head part is tested, and if the pattern doesn't match, the test from Condition or PatternTest is simply not performed. So yes, this is a particular form of short-circuiting, very sensible one IMO. I have discussed it in this answer. $\endgroup$ Commented Dec 29, 2015 at 22:43

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.