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$ Commented 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$ Commented Mar 28, 2019 at 19:48
  • 1
    $\begingroup$ One might be able to do what OP want by leveraging with OneIdentity. $\endgroup$
    – Silvia
    Commented 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
    Commented 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
    Commented 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
    Commented Mar 29, 2019 at 6:20
  • $\begingroup$ @Roman With pleasure. If there are more ‘elegant’ approaches, please let me know. $\endgroup$ Commented Mar 29, 2019 at 11:13
  • $\begingroup$ I've adopted your solution for the linked problem at mathematica.stackexchange.com/a/194103 $\endgroup$
    – Roman
    Commented 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
    Commented 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
    Commented 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
    Commented Apr 6, 2019 at 10:42

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