2
$\begingroup$

I want to bind arguments to methods (e.g. for use in OOP creating a bound method--what Java just calls a method). I realized this is basically just a partial function application. Now I want to make this in Mathematica.

My hope is to to make a PartialFunction object that formats nicely and uses HoldAllComplete when passing arguments through so as to really do nothing to them.

Of course, I can just do this:

partialFunction[func_, params__] :=
 Function[Null, func[params, ##], HoldAllComplete]

But this is just ugly to look at and gives me no hint as to what the Options are. Cleaner would be to do something like this:

partialFunction[func_Symbol, params__] :=

  Module[{func, cached = func},
   Options[func] = Options[cached];
   func[args___] :=
    cached[params, args];
   Format[func] =
    RawBoxes@
     BoxForm`ArrangeSummaryBox[
      "partialFunction",
      func,
      None,
      {
       cached,
       BoxForm`MakeSummaryItem[{"Args: ",  Length@{params}}, 
        StandardForm]
       },
      {},
      StandardForm
      ];
   func~SetAttributes~HoldAllComplete;
   func
   ];
partialFunction[func_, params__] :=

 Function[Null, func[params, ##], HoldAllComplete]

Which looks fine, preserves options, and is almost perfect except for that pesky detail of creating terrible memory leaks.

Consider the following:

m1 = Module[{m1 = MemoryInUse[]},
   partialFunction[Print, RandomReal[{}, {1000, 1000}]];
   m1
   ];
MemoryInUse[] - m1

8006848

Because Print is on the RHS of my partialFunction function that large matrix I created won't go out-of-scope until Print does. This is discussed here. That seems to nix this otherwise really clean approach.

So how can we get partial function application that's nicer than just using Function?

$\endgroup$
2
$\begingroup$

If you don't mind doing some radical surgery on Function, you could do the following:

PartialFunction[s_, p__] := Function[Null, ipf[s, p, ##], HoldAllComplete]

Unprotect[Function];
MakeBoxes[Function[Null, ipf[s_, p__, ##], HoldAllComplete], StandardForm] ^:= 
BoxForm`ArrangeSummaryBox[
    "PartialFunction",
    s,
    None,
    {s, BoxForm`MakeSummaryItem[{"Args: ", Length@Hold[p]}, StandardForm]},
    {},
    StandardForm
];
HoldPattern[Options[Function[Null, ipf[s_, __], HoldAllComplete]]] ^:= Options[s]
Protect[Function];

SetAttributes[ipf, HoldAllComplete]
ipf[sym_, params_, args__] := sym[params, args]

(it would be better to make this a package so that ipf could be a private symbol) For example:

pf = PartialFunction[Integrate, x^2]

enter image description here

and:

pf[{x,0,1}]
pf[{x,0,10}]

1/3

1000/3

Also, Options works as desired:

Options[pf]

{Assumptions :> $Assumptions, GenerateConditions -> Automatic, PrincipalValue -> False}

If the parameter is large, than the PartialFunction will be large, but there is no memory leak:

MemoryInUse[]
Module[{pf = PartialFunction[Print, RandomReal[1, {1000, 1000}]]},
    MemoryInUse[]
]
MemoryInUse[]

319084696

327086744

319086640

$\endgroup$
  • $\begingroup$ This is pretty good... I'm a bit concerned about fragility given the overloads and things, but overall it's a nice approach. $\endgroup$ – b3m2a1 Oct 18 '18 at 8:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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