Simplest solution
Use Set
instead of SetDelayed
:
vl = {a_, m_, s_, τ_, c_, x$HH_, x$HF_, x$FF_, x$FH_, λ$H_, λ$F_, L$H_, L$F_, w_, δ_};
vle = {a, m, s, τ, c, x$HH, x$HF, x$FF, x$FH, λ$H, λ$F, L$H, L$F, w, δ};
vle1 = {1, 1, 1, 1, 1, 1, 1, x$FF, x$FH, λ$H, λ$F, L$H, L$F, w, 1};
xx[vl] = vle;
xx[vle1]
xx[2 vle1]
(* {1, 1, 1, 1, 1, 1, 1, x$FF, x$FH, λ$H, λ$F, L$H, L$F, w, 1} *)
(* {2, 2, 2, 2, 2, 2, 2, 2 x$FF, 2 x$FH, 2 λ$H, 2 λ$F, 2 L$H, 2 L$F, 2 w, 2} *)
This has pitfalls and does not quite address all the conditions set out in the OP's question. First, if the variables in vle = {a,...}
have values, then they will be used instead of the symbols when xx
is defined. If for instance a = 43
at the time xx[vl] = vle
is executed, then xx[vle1]
would return {43, 1,...}
. Assuming vl
is a flat list of named patterns, a workaround is to block all the symbols used as pattern names using an injector pattern:
Hold @@ vl /. Verbatim[Pattern][v_, _] :> v /. Hold[vars___] :>
Block[{vars}, xx[vl] = vle]
Second, this solution doesn't satisfy the desired property that the definition depends on vl
. The symbol vl
is evaluated and replaced by an explicit list of argument patterns before the down-value for xx
is created.
??xx
(*
xx[{a_,m_,s_,τ_,c_,x$HH_,x$HF_,x$FF_,x$FH_,λ$H_,λ$F_,L$H_,L$F_,w_,δ_}] =
{a,m,s,τ,c,x$HH,x$HF,x$FF,x$FH,λ$H,λ$F,L$H,L$F,w,δ}
*)
The solution f[argList] := a + b + c
by djp also has this drawback. In both solutions, xx
has to be redefined if vl
is changed.
Solution to an implicit question
It's really annoying to spend the time seeking what variables I could miss...
Here is a function that will check the definitions (i.e. each down value) of a function and report Global`
symbols present in the definition but missing from the arguments. (There seemed to me to be both advantages and disadvantages to making getHeldSymbols
and getHeldPatternNames
both HoldAll
and adapting the code of missingArgs
to those attributes. I could not decide which way was best.)
ClearAll[getHeldSymbols, getHeldPatternNames];
getHeldSymbols[e_] := DeleteDuplicates@
Cases[e, v_Symbol /; Context[v] === "Global`" :> Hold[v], Infinity];
getHeldPatternNames[e_] := DeleteDuplicates@
Cases[e, Verbatim[Pattern][v_, _] :> Hold[v], Infinity]
ClearAll[missingArgs];
missingArgs::nofn = "Symbol `` has no down values.";
missingArgs[f_Symbol] /; DownValues[f] =!= {} :=
missingArgs /@ DownValues[f];
missingArgs[Verbatim[HoldPattern][f_[args___]] :> val_] :=
HoldPattern[f[args]] -> Complement[
getHeldSymbols[Hold[val]],
getHeldPatternNames[Hold[args]]
];
missingArgs[f_Symbol] := Message[missingArgs::nofn, f];
Examples:
Clear[f];
f[a_, b_, c_] := a + b + c;
missingArgs[f]
(*
{HoldPattern[f[a_, b_, c_]] -> {}}
*)
Clear[f];
f[a_, b_, c_] := a + Exp[c] + d;
missingArgs[f]
(*
{HoldPattern[f[a_, b_, c_]] -> {Hold[d]}}
*)
Clear[f];
f[a_, b_, c_] := a + b + c + d;
f[{a_, b_, c_}] := a + Exp[c] + e;
missingArgs[f]
(*
{HoldPattern[f[a_, b_, c_]] -> {Hold[d]},
HoldPattern[f[{a_, b_, c_}]] -> {Hold[e]}}
*)
Improvement or triviality? Re my original interpretation and solution
The problem originally appeared to me to be one of constructing a function definition that would at run-time adapt to a dynamically changing argument pattern. In its general scope, such a problem is not a duplicate of Can a function be made to accept a variable amount of inputs?. The MWE, which might not reflect the subtleties of the general use-case, might be solved with code like one of the following or approaches from the linked question:
f[{a_, b_, c_, ___}] := a + b + c;
f[list_] /; Length[list] >= 3 := Total[list[[ ;; 3]]];
On the other hand, most situations do not require such indirect function construction as shown below, and I have to echo Szabolcs's comment that there is probably a better approach.
Indeed, here's a general solution for creating a delayed function evaluation that adapts to changes to the argument pattern, but which raises the question of the triviality of the problem. It stores the argument patterns and replacement value in delayedFunction
, which is evaluated when passed an input.
ClearAll[setDelayedDelayed, delayedFunction];
SetAttributes[setDelayedDelayed, HoldAll];
SetAttributes[delayedFunction, HoldAll];
setDelayedDelayed[f_Symbol, args_, val_] /; ListQ[args] :=
f = delayedFunction[args, val];
With[{f = Unique[]},
delayedFunction[args_, val_][x___] /; MatchQ[{x}, args] :=
Thread[getHeldPatternNames[Evaluate@args], Hold] /.
Hold[vars_] :> Block[vars, Block @@ Hold[{f}, (f[##] = val) & @@ args; f[x]]]
];
Example:
Clear[xx, a];
vl = {a_, m_, s_, τ_, c_, x$HH_, x$HF_, x$FF_, x$FH_, λ$H_, λ$F_, L$H_, L$F_, w_, δ_};
vle = {a, m, s, τ, c, x$HH, x$HF, x$FF, x$FH, λ$H, λ$F, L$H, L$F, w, δ};
a = 43; (* to verify that a is blocked *)
setDelayedDelayed[xx, {vl}, vle]
(* delayedFunction[{vl}, vle] *)
xx[vle1]
(* {1, 1, 1, 1, 1, 1, 1, x$FF, x$FH, λ$H, λ$F, L$H, L$F, w, 1} *)
AppendTo[vl, dummy_] (* add an extra argument to vl *)
(* {a_, m_, s_, τ_, c_, x$HH_, x$HF_, x$FF_, x$FH_, λ$H_, λ$F_, L$H_, L$F_, w_, δ_,
dummy_} *)
xx[Append[vle1, extra]] (* and an extra input *)
(* {1, 1, 1, 1, 1, 1, 1, x$FF, x$FH, λ$H, λ$F, L$H, L$F, w, 1} *)
What the code shows, Mathematica already has such functions for constructing functions at run-time, namely Set
and SetDelayed
(even ReplaceAll
could be used). The only nontrivial aspect is localizing the arguments in args
and val
. But that can be done as shown at the end of the simplest answer. One of the sillier things about the delayedFunction
solution is that the function is basically constructed each time it is evaluated. This is probably fast in almost all cases, so it is not terribly inefficient.
Original solution
In any case, working from my initial interpretation, it seems to me that if the list of arguments changes, the expression the function computes might change, too. There are two forms for the argument pattern, one which appears in the OP's question and one that appears in djp's answer. It is easy to give both.
arglist = {a_, b_, c_};
expr = a + b + c;
Clear[f];
f[x_] /; MatchQ[x, arglist] :=
x /. arglist -> (Hold[expr] /. OwnValues[expr]) // ReleaseHold
f[{x, y, z}]
(* x + y + z *)
Clear[f];
f[x__] /; MatchQ[{x}, arglist] :=
{x} /. arglist -> (Hold[expr] /. OwnValues[expr]) // ReleaseHold
f[x, y, z]
(* x + y + z *)
arglist = {a_, b_, c_, d_};
expr = a + b + c + 2 d;
f[x, y, z, w]
(* 2 w + x + y + z *)
If any of the variables have a value, then the values will be substituted in the assignment to expr
, which is probably an undesired behavior. A way around this is to Block
the variables while expr
is being defined.
Block @@ (Hold[#,
expr = a + b + c + d
] &@arglist /. Verbatim[Pattern][x_, _] :> x)
With[{list = {a_, b_, c_}}, f[list] := a + b + c]
. Try not to do this. Also, this won't work in every situation. I really can't understand why you can't just inlinelist
. Why don't you explain in more detail what you are trying to achieve? There's very likely a much better solution. $\endgroup$f[a_,b_,c_]
? The reason is that I ahve a lot of function definition. And some functions need already defined functios. Like:p$HH[x$HH_] := Derivative[1, 0, 0][u][x$HH, a, m]/\[Lambda]$H
p$HF[x$HF_] := Derivative[1, 0, 0][u][x$HF, a, m]/\[Lambda]$F
\[Nu]$H[L$H_, L$F_, x$HH_, x$HF_, \[Tau]_, f_] := (L$H*p$HH[x$HH]*x$HH + L$F*p$HF[x$HF]*x$HF - w*(c*(L$H*x$HH + \[Tau]*L$F*x$HF) + F))
And if I forgot to include any small variable it doesn't work and it is not convinient.... $\endgroup$f[list_]:=Total@list
solve it? (ahem, this is what @sektor meant withApply
) $\endgroup$