1
$\begingroup$

How can I construct a pattern that matches both f and h[f] without using the symbol f more than once in the pattern definition? That is, how can I define a pattern pattern that allows for an optional head, and returns {True, True} when used in

MatchQ[pattern] /@ {f, h[f]}

I don't want to use the alternative pattern pattern = f | h[f].

I've tried

pattern = (Identity | h)[f];
MatchQ[pattern] /@ {f, h[f]}
(* {False, True} *)

which matches h[f] but not f; it would only match an unevaluated Identity[f]. Is there a way to evaluate the pattern before application so that Identity[f] becomes f and matches?

See also here.

$\endgroup$
12
  • 2
    $\begingroup$ Why is it so crucial to only use f once in the pattern? What's wrong with something like f[_] | Derivative[__][f][_]? You can always use something like With[{symbol = f}, ...] if you want to write f only once. $\endgroup$ Mar 28, 2019 at 19:35
  • 2
    $\begingroup$ Maybe someone knows a trick I don't know, but I don't think you can do this any more elegantly than with Alternatives. I don't know of any way to match an optional head-of-a-head like you're trying to do here. Optional or BlankNullSequence don't work here at least. $\endgroup$ Mar 28, 2019 at 19:48
  • 1
    $\begingroup$ One might be able to do what OP want by leveraging with OneIdentity. $\endgroup$
    – Silvia
    Apr 1, 2019 at 21:08
  • 1
    $\begingroup$ I seems to not being able to come up a pattern simple while not matching almost everything. $\endgroup$
    – Silvia
    Apr 3, 2019 at 6:14
  • 1
    $\begingroup$ @Silvia the issue seems to be this point in the documentation ("possible issues") of OneIdentity: "In order for f[a] to match a, you must use a pattern that includes Optional." As you say, the resulting pattern then matches almost anything. $\endgroup$
    – Roman
    Apr 3, 2019 at 19:10

2 Answers 2

7
+200
$\begingroup$

I find that Through will make it work:

pattern = Through[(Identity | h)[f]];
MatchQ[pattern] /@ {f, h[f]}
{True, True}

But it works just because in fact Through transforms (Identity | h)[f] into f | h[f].

$\endgroup$
13
  • $\begingroup$ That's a start, thanks. I guess I'd like to transform/execute the pattern at match-time, not at define-time; but the idea is there in your solution. $\endgroup$
    – Roman
    Mar 29, 2019 at 6:20
  • $\begingroup$ @Roman With pleasure. If there are more ‘elegant’ approaches, please let me know. $\endgroup$ Mar 29, 2019 at 11:13
  • $\begingroup$ I've adopted your solution for the linked problem at mathematica.stackexchange.com/a/194103 $\endgroup$
    – Roman
    Mar 29, 2019 at 11:18
  • $\begingroup$ I know it's not what you are looking for, but pattern := Through[(Identity | h)[f]] doesn't transform at definition time. $\endgroup$
    – mikado
    Mar 31, 2019 at 11:14
  • $\begingroup$ That's right @mikado, but as soon as I use the pattern in a non-delayed setting it gets evaluated right away. For example, define Q[x : Through[(Identity | h)[f]]] = x and then check ?Q: you see that the definition of Q contains the evaluated alternative pattern f|h[f]. $\endgroup$
    – Roman
    Mar 31, 2019 at 17:11
1
$\begingroup$

You may use Condition.

MatchQ[a_ /; (Last@Level[a, {-1}] == f)] /@ {f, h[f]}
{True, True}

Or PatternTest

MatchQ[a_?(Not@*FreeQ[f])] /@ {f, h[f]}
{True, True}

Hope this helps.

$\endgroup$
1
  • $\begingroup$ These conditional patterns all match too broadly: they'll match all of {f, h[f], g[f], h[h[f]]} etc. Is there a way of constraining them? $\endgroup$
    – Roman
    Apr 6, 2019 at 10:42

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.