# Pattern-matching Function with conditions on arbitrary number of arguments

I'm trying to add a long list of pattern matching conditions to an existing function, which takes a variable number of arguments.

I know there are similar threads on this topic, but I was unable to make them work for the particular example I'd like to do.

Take the condition that says numerical objects should be factored out of the function argument.

lol[c_?NumericQ d_] := c lol[d]

lol[2]
lol[2 kk]

(* -> lol[2] *)
(* -> 2 lol[kk] *)


Now I would like it to be able to apply this condition to an arbitrary number of slots. For example I would like to write something like

lol[c_?NumericQ d__] := c lol[d]

lol[2]
lol[2 kk]
lol[2 kk, 3 jj]

(* -> lol[2] *)
(* -> 2 lol[kk] *)
(* -> 6 lol[kk,jj] *)


lol[2 kk, 3 jj]


simply returns

(* -> lol[2 kk, 3 jj] *)


Just to emphasise: it must be able to handle any number of inputs, I can't just code rules for 2 slots in addition to the rule for 1 slot. And the goal is to be able to update the properties of "lol" as a function, not just to produce a procedure that can factor Numeric objects out of functions (because I have an existing function that needs to have these properties but is too lengthy to paste her).

• This looks to be a problem where both the input and output arguments of lol should be lists. You may then also want to consider ReplaceAll. – DavidC Nov 13 '16 at 14:21
• I'm just wondering if I'll be able to use ReplaceAll to update the properties of an existing function... will give it a try – Jonathan Rayner Nov 13 '16 at 15:09

lol[left___, c_?NumericQ d_, right___] := c lol[left, d, right]

• Can this approach handle the case of multiple slots with numerical multipliers as requested in the question? – MarcoB Nov 14 '16 at 1:06
• @MarcoB Yes, it can. – QuantumDot Nov 14 '16 at 1:13
• Confirmed, works perfectly on any number of slots. @QuantumDot Can you explain why it works? I've tried to think through what procedure Mathematica follows with the case of 1, 2, or 3 slots, but I'm lost. – Jonathan Rayner Nov 14 '16 at 6:48
• @JonRayner ___ is BlankNullSequence and represents any number of arguments. When the pattern matcher encounters this in a pattern, it tries all possible combinations to match the pattern. – QuantumDot Nov 14 '16 at 14:52

I've got

lol[x : (PatternSequence[_?NumericQ _Symbol] ..)] :=
(Times @@ {x}[[All, 1]]) lol[Sequence @@ {x}[[All, 2]]]


which gives

lol[2 k, 3 j]


6 lol[k, j]

lol[2 k, 3 j, 5 m]


30 lol[k, j, m]

Caveats:

lol[2 k, j]


lol[2 k, j]

lol[2 k, 1 j]


lol[2 k, j]

but

lol[2 k, 1. j]

1. lol[k, j]

Also

lol[2 k, 7]


lol[2 k, 7]

but I'm not sure what should the function do in this case.

And a brute one:

Clear[lol]
lol[x__] :=
Module[{y = List@x, coeffs, vars, c},
vars = Variables /@ y // Flatten;
coeffs = Coefficient[##] & @@@ Transpose@{y, vars};
c = Times @@ coeffs; c Defer@lol[##] & @@ vars]

lol[2 k, j]


2 lol[k, j]