1

I would like to define an operator that takes some parameters as input and returns a function. Here is an example:

operator[indexLists_] := Function[weights,Table[Total[weights[[indexLists[[i]]]]], {i, Length[indexLists]}]];
example = {{1, 2, 3}, {5, 2, 1}, {1, 2}, {6, 7}};
op1 = operator[example]

which returns

Function[weights$, Table[Total[
   weights$[[{{1, 2, 3}, {5, 2, 1}, {1, 2}, {6, 7}}[[i]]]]], {i, Length[{{1, 2, 3}, {5, 2, 1}, {1, 2}, {6, 7}}]}]]

what I would want is a partially evaluated version, i.e.

op2 = Function[weights, {Total[weights[[{1, 2, 3}]]], Total[weights[[{5, 2, 1}]]], Total[weights[[{1, 2}]]], Total[weights[[{6, 7}]]]}]

Both op1 and op2 return functions that perform the same thing, e.g. when called with "Range[8]" as argument they return {6, 8, 3, 13}.

This is a toy example. In my real example, the function returned by the operator performs some complex transformation of the input parameter "weights" that I want to pre-compute in order to be more efficient when evaluating the function many times. I could not figure out how to get around to HoldAll attribute of the pure function.

Beginner
  • 443
  • 2
  • 6

2 Answers2

1

One idea is to use Inactive/Activate:

operator[indexLists_] := Block[{weights},
    Activate @ Inactive[Function][
        weights,
        Table[Inactive[Total][Inactive[Part][weights,indexLists[[i]]]],{i,Length[indexLists]}]
    ]
]

Inactivating Function wasn't strictly necessary, but it prevented the variable weights from being modularized to weights$. Inactivating Total and one of the Part functions prevented undesired evaluations. Your example:

example = {{1,2,3},{5,2,1},{1,2},{6,7}};
op1 = operator[example]

Function[weights, {Total[weights[[{1, 2, 3}]]], Total[weights[[{5, 2, 1}]]], Total[weights[[{1, 2}]]], Total[weights[[{6, 7}]]]}]

and

op1[Range[8]]

{6, 8, 3, 13}

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
1

An approach to circumvent the HoldAll attribute is to "inject" the expressions into Function after (partially) evaluating them:

operator[indexLists_] := 
 Block[{weights, f}, 
  Function[weights, #] & @Thread[f[weights, indexLists]] /. 
   f[xx__] :> Total[Part[xx]]]

Inside Block, I clear not only the variable weights but also an auxiliary f that is replaced at the very end with Total[Part[...]]. This replacement rule is one way to inject things into held expressions. Before that, I first create a slot # inside Function into which I insert the evaluated Table generated by the indexList argument to operator. This is where the temporary name f is used as a placeholder for the desired operation which can't be executed at that stage. It creates the necessary structure inside Function into which the replacement rule then inserts Total[Part[...]].

Jens
  • 97,245
  • 7
  • 213
  • 499