# pure Function[ ] named formal parameters

I am trying to setup a bunch of pure Functions in particular with an identical rahter long parameter list.

({a, b, c, d, e, f} \[Function] a + b)[r, s, t, u, v, w]
({a, b, c, d, e, f} \[Function] a*f)[r, s, t, u, v, w]
({a, b, c, d, e, f} \[Function] a*b/c)[r, s, t, u, v, w]


this works as expected:

r+s
r w
(r s)/t


Now I would like to put the formal parameter List in a variable:

pl = {a, b, c, d, e, f};
(Evaluate@pl \[Function] a + b)[r, s, t, u, v, w]
(Evaluate@pl \[Function] a*f)[r, s, t, u, v, w]
(Evaluate@pl \[Function] a*b/c)[r, s, t, u, v, w]


So far this works too an gives the sam result as above.

But there is a problem with the localization of the formal parameters. If I e.g. assign a value to the global Symbol a:

a=42;


I get an Error:

Function::flpar: Parameter specification {42,b,c,d,e,f} in Function[{42,b,c,d,e,f},a+b] should be a symbol or a list of symbols.


Any hints how to solve this problem? Have already tried various combinations of the usual suspects (Hold, Symbol, ...)

Kind Regards Robert

Ok, very close related to the first question I got a second one.

How can I get the SymbolName's of the Symbol's listed in pl? The need for this feature is e.g. to form a Table with TableForm and TableHeadings -> {None, pl}

a = 42;
pl := {a, b, c, d, e, f};

TableForm[{{1, 2, 3, 4, 5, 6}, {10, 20, 30, 40, 50, 60}}, TableHeadings -> {None, pl}]

5   b   c   d   e   f
1   2   3   4   5   6
10  20  30  40  50  60


As can bee seen the assignment to a spoils everything.

I have a little bit nasty solution via string matching:

OwnValues@pl // ToString //
StringCases[#, __~~"{"~~s__~~"}"~~__ :>StringSplit[s, ", "]] &//First

{"a","b","c","d","e","f"}


Can this be don more elegantly?

• Can you put this into context? What are you really trying to do? There may be better approaches. Commented Jun 15, 2018 at 10:40
• Well, I have tabular data (2D List), each column for some property. Each row for a set of this properties. I want to Map[Apply] various functions/evaluations for every row of this data. Not in one place but spread on different positions in a notebook. So all the functions share the same parameter list. If for some reason the layout of the data changes I would like to have on central parameter list for all the functions to be adjusted. Commented Jun 15, 2018 at 11:13
• Why not use formal variables instead, e.g., \[FormalA], \[FormalB] etc instead of a, b etc Commented Jun 17, 2018 at 13:28
• @Carl Woll can you clarify your suggestion Commented Jun 18, 2018 at 14:18
• Formal variables are protected, so you can’t give them values, and so you don’t have to worry about them having OwnValues Commented Jun 18, 2018 at 14:33

Would it be acceptable for you?

a = d = 2 (*just to test*)

myFunction // ClearAll
myFunction // Attributes = {HoldAll};
myFunction[expr_] := Function @@ Unevaluated[{{a, b, c, d, e, f}, expr}]


You can use your function constructor anywhere:

myFunction[a + b] @@ {1, 2, 3, 4, 5, 6}


3

and if data structure changes, you can redefine it with e.g....[{{a, c, d, e, f, b}, expr}]

And now:

  myFunction[a + b] @@ {1, 2, 3, 4, 5, 6}


7

p.s. Function @@ is there for Enforcing correct variable bindings and avoiding renamings for conflicting variables in nested scoping constructs

• You could also use Hold instead of Unevaluated for similar effect, I think Commented Jun 17, 2018 at 0:47
• @b3m2a1 yes, this time it was an overreaction
– Kuba
Commented Jun 17, 2018 at 8:23
• I’m not sure it was an overreaction :) but perhaps a bit more complicated than you needed Commented Jun 17, 2018 at 8:33

Thanks @xzczd and @Kuba

Based on your suggestions I came up with two (three) versions, the second one with an individual parameter list which in turn is passed as a parameter:

a = 42;
pl := {a, b, c, d, e, f};
gl := {a, b, d, c, e, f};

Attributes[buildfunc] = {HoldAll};
buildfunc[body_] := (F \[Function] F[pl, body] /. OwnValues@pl)@Function
buildfunc[body_,
pl_Symbol] := (F \[Function] F[pl, body] /. OwnValues@pl)@Function
buildfunc[body_, pl_List] := (F \[Function] F[pl, body])@Function

buildfunc[c - d]
buildfunc[c - d, gl]
buildfunc[c - d, {a, b, d, c, e, f}]

buildfunc[c - d][r, s, t, u, v, w]
buildfunc[c - d, gl][r, s, t, u, v, w]
buildfunc[c - l, {a, b, f, c, e, l}][r, s, t, u, v, w]


gives:

Function[{a, b, c, d, e, f}, c - d]
Function[{a, b, d, c, e, f}, c - d]
Function[{a, b, d, c, e, f}, c - d]

t - u
-t + u
u - w


Seems to work pretty well. Note the last usage with direct feed of a parameter list actually counteracts the original intention

a = 42;
pl := {a, b, c, d, e, f};
SetAttributes[buildfunc, HoldAll]
buildfunc[body_] := (Unevaluated[#[pl, body]] /. OwnValues@pl) &@Function
(* Alternatively: *)
(*
buildfunc[body_] := Function @@ Append[Trace[pl][[2]], Unevaluated@body]
*)

buildfunc[c + d]
pl := {a, e, f}
buildfunc[e - f]


# Update

As you've noticed, the new problem is similar to the original, so it can be solved in a similar manner:

a = 42;
pl := {a, b, c, d, e, f};

ClearAll[nameonly]
SetAttributes[nameonly, HoldAll]

nameonly[lst_] := HoldForm[lst] /. OwnValues@lst // Thread
(* Alternatively: *)
(*
*)
TableForm[{{1, 2, 3, 4, 5, 6}, {10, 20, 30, 40, 50, 60}},


If you need a list of string as the output, you can:

(* Solution 1 *)
nameonly@pl /. HoldForm[a_] :> SymbolName@Unevaluated@a
(* Solution 2 *)
Function[a, SymbolName@Unevaluated@a, HoldAll] @@@ nameonly@pl

• This is not a solution, because the Global a is destroyed, exactly this behavior should be avoided. The Symbol a should be kept local. Commented Jun 15, 2018 at 11:22
• @RobertNowak As far as I can tell, if an answer doesn't meet the requirement of asker, then editing the body of answer to improve or correct it rather than posting a new answer is the proper thing to do. Commented Jun 15, 2018 at 12:22
• @RobertNowak Again, check my edit. And, you should clarify all of these in the body of your question. Commented Jun 15, 2018 at 12:36
• @RobertNowak I'm afraid the first problem won't be easier to solve, because you'll have to transform strings to symbols in some stage if you want to define function. And, I believe string will probably make things more troublesome. A solution I can think out at the moment: a = 42; pl := {"a", "b", "c", "d", "e", "f"}; ClearAll[buildfunc]; SetAttributes[buildfunc, HoldAll]; buildfunc[body_] := Function[Join @@ ToExpression[pl, InputForm, HoldPattern] // Evaluate, body] /. HoldPattern -> List // Quiet Commented Jun 18, 2018 at 14:11
• ok, managed it to get a little of a bit nicer version on the List of String's buildfunc[body_] := Hold[Function][ToExpression[pl, InputForm, Hold], Hold[body]] // ReleaseHold Commented Jun 21, 2018 at 15:04