1
$\begingroup$

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.

$\endgroup$
1

2 Answers 2

1
$\begingroup$

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}

$\endgroup$
1
$\begingroup$

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[...]].

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.