1

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.

Roman
  • 47,322
  • 2
  • 55
  • 121
  • 2
    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. – Sjoerd Smit Mar 28 '19 at 19:35
  • @SjoerdSmit I'm trying to learn more about pattern matching and feel like I'm missing a puzzle piece here. Your workarounds are of course valid but they aren't what I'm looking for. – Roman Mar 28 '19 at 19:36
  • 2
    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. – Sjoerd Smit Mar 28 '19 at 19:48
  • @SjoerdSmit what about using some kind of Default? I don't know how to use it here though as I'm trying to default the head, not an argument as usual. – Roman Mar 28 '19 at 19:50
  • Simplified the question now: removed the irrelevant discussion of Derivative, so the focus is on the optional head issue. – Roman Mar 28 '19 at 20:13
  • So could you please give a list of expressions and indicate which should be matched and which others should not? – Αλέξανδρος Ζεγγ Mar 29 '19 at 02:06
  • @ΑλέξανδροςΖεγγ I've added a minimal list that needs to be matched. – Roman Mar 29 '19 at 05:47
  • 1
    One might be able to do what OP want by leveraging with OneIdentity. – Silvia Apr 01 '19 at 21:08
  • @Silvia this could be the ticket! I didn't realize what this attribute was for until you commented. Why don't you amplify this comment into an answer? – Roman Apr 02 '19 at 19:12
  • 1
    I seems to not being able to come up a pattern simple while not matching almost everything. – Silvia Apr 03 '19 at 06:14
  • @Silvia I will try too when I finally get to a computer. Thanks for trying. – Roman Apr 03 '19 at 11:27
  • 1
    @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. – Roman Apr 03 '19 at 19:10

2 Answers2

7

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].

  • 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. – Roman Mar 29 '19 at 06:20
  • @Roman With pleasure. If there are more ‘elegant’ approaches, please let me know. – Αλέξανδρος Ζεγγ Mar 29 '19 at 11:13
  • I've adopted your solution for the linked problem at https://mathematica.stackexchange.com/a/194103 – Roman Mar 29 '19 at 11:18
  • I know it's not what you are looking for, but pattern := Through[(Identity | h)[f]] doesn't transform at definition time. – mikado Mar 31 '19 at 11:14
  • 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]. – Roman Mar 31 '19 at 17:11
  • @Roman Not sure if this is exactly the same thing or not: pattern = (h[#] | #) &[f, Identity] – MelaGo Apr 03 '19 at 02:44
  • @MelaGo this is exactly the same alternative pattern, as it evaluates immediately to pattern = h[f] | f when the first argument f is inserted into the anonymous function. The second argument Identity in your list of arguments is unused; what was your idea for putting it there? – Roman Apr 04 '19 at 09:49
  • @Roman Hmm good point, I don't know what I was thinking. How about pattern = h_: Null[f]? – MelaGo Apr 04 '19 at 19:27
  • @MelaGo this matches f as well as h[f]! For the wrong reasons though, as (1) it matches g[f] as well (it's not specific to h as a head), and (2) Optional::optloose is thrown and the default value Null is not used at all (you can replace it by anything else). After all, MatchQ[f, Null[f]] would have returned False. – Roman Apr 04 '19 at 20:18
  • @Roman You're right that's awful. OK this is my last try, I promise. You're not going to like it: StringMatchQ[ToString[#], RegularExpression["(h\[)*f\]*"]] – MelaGo Apr 04 '19 at 21:29
  • Thanks @MelaGo that's very creative! With the RegExp "(h[)?f]?" it works even better as this doesn't match h[h[f]] etc. Technically it's a valid solution, but you're right I don't like it in this context. Thanks a lot! – Roman Apr 04 '19 at 21:57
  • @Roman One more. (MatchQ[Head[#], (h | Symbol)] && MatchQ[Switch[Length[#], 0, #, 1, #[[1]]], f]) – MelaGo Apr 05 '19 at 01:17
  • @MelaGo that works as well but it's two patterns, not a single one. Thanks a lot for your input, I'll be thinking more about this and maybe something comes together from all of these partial solutions! – Roman Apr 05 '19 at 07:23
1

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.

Edmund
  • 42,267
  • 3
  • 51
  • 143
  • 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? – Roman Apr 06 '19 at 10:42