5
$\begingroup$

I need to match a products with exactly one factor F, an arbitrary number of factors of head A, and possibly additional inert factors. I'm having trouble writing one pattern that can capture all the following cases.

I tried the following rule (the c term is there for show)

rule1 = Times[ayes___A, F] :> func[Times[ayes], F];

c + F             /. rule1
c + A[x] F        /. rule1
c + A[x] A[y] F   /. rule1
c + d A[x] A[y] F /. rule1
c + F                        (*desired: c + func[1,F]  *)
c + func[A[x], F]            (*correct*)
c + func[A[x] A[y], F]       (*correct*)
c + d func[A[x] A[y], F]     (*correct*)

The first expression failed to properly match, because it doesn't have head Times. Then I tried a second rule with Optional:

rule2 = rule2 = Times[Optional[ayes__A], F] :> func[Times[ayes], F];

(*Input same as above but with /. rule2*)
c + func[1,F]                (*correct*)
c + func[A[x], F]            (*correct*)
c + func[A[x] A[y], F]       (*correct*)
c + d A[x] A[y] func[1, F]   (*desired: c + d func[A[x] A[y], F] *)

This time the fourth expression failed to match because of the extra factor. So now I try a third rule to accommodate that extra factor:

rule3 = Times[extra_. Optional[ayes__A], F] :> extra*func[Times[ayes], F]

(*Input same as above but with /. rule3*)
c + func[1,F]              (*correct*)
c + func[A[x], F]          (*correct*)
c + A[y] func[A[x], F]     (*desired: c + func[A[x] A[y], F]*)
c + d A[y] func[A[x], F]   (*desired: c + d func[A[x] A[y], F] *)

Now the pattern matcher got confused probably because of all the optional arguments.

Is there a single pattern that can match all these cases? Since I'm working with potentially large expressions, I would also prefer to avoid using pattern tests (Conditional) for performance reasons.

$\endgroup$
3
  • 1
    $\begingroup$ Does this get them all? Times[a_. ayes__A, F] | a_. F :> a func[Times[ayes], F]? $\endgroup$
    – march
    Commented Mar 20, 2016 at 22:23
  • $\begingroup$ @march It doesn't get the third expression properly, c + A[y] func[A[x], F] $\endgroup$
    – QuantumDot
    Commented Mar 20, 2016 at 22:56
  • $\begingroup$ Right. Missed that one. I still think Alternatives is the way to go, although I'm not sure if it has the same performance hit as using pattern tests. For instance, rule1 = Times[ayes__A, F] | Times[a_ ayes__A, F] | a_. F :> a func[Times[ayes], F];. $\endgroup$
    – march
    Commented Mar 20, 2016 at 22:59

1 Answer 1

2
$\begingroup$

ReplaceAll can use a list of rules.

Here the first rule in the list addresses Times and F. The second rule (which is only invoked if the first rule is not used) addresses Plus and F.

rule = {Times[F, extra_., ayes__A] ->  extra func[Times[ayes], F],
  c_ + F -> c + func[1, F]}

Now

c + F             /. rule
c + A[x] F        /. rule
c + A[x] A[y] F   /. rule
c + d A[x] A[y] F /. rule

produces

c + func[1, F]
c + func[A[x], F]
c + A[x] func[A[y], F]
c + d func[A[x], A[y], F]
$\endgroup$

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.