10
$\begingroup$

Is there a programmatic way to convert a Mathematica rule that acts like a typical mathematical function of one variable into the equivalent pure function? For example, the code should convert

f[x_] := x Sin[x^2]

into

Function[# Sin[#^2]]

and also convert

g[x_] := Piecewise[{{0,x<8.}, {2.5,8.<=x<18},{0,x>18}}]

into

Function[ Piecewise[{{0,#<8.}, {2.5,8.<=#<10},{0,#>18}}] ]

It's important that the result not reference the original function or the symbol used for it, so that the resulting pure function continues to work even if the original function-like rule is redefined or cleared.

Thanks...

$\endgroup$
  • $\begingroup$ To clarify: I need to write code that can take any function-like rule it's handed, and convert it into a pure function. Let's instantiate this as a function ruleToFunction[rule_]:=... that returns a pure function corresponding to whatever rule it was given. So, ruleToFunction[f] would return Function[# Sin[#^2]], using my above example. $\endgroup$ – ibeatty Mar 16 '15 at 20:46
10
$\begingroup$
ClearAll[ruleToFunction, f1, f2];

ruleToFunction[func_] := Function[, Evaluate@func[Slot[1]]];

g[x_] := Piecewise[{{0, x < 8.}, {2.5, 8. <= x < 18}, {0, x > 18}}]

f1 = ruleToFunction[g]
ClearAll[g];
f1@10

f[x_] := x Sin[x^2]

f2 = ruleToFunction[f]
ClearAll[f];
f2@10

enter image description here

$\endgroup$
  • $\begingroup$ It works! (I removed the comma in your definition of ruleToFunction, and it still seemed to work. Having a comma without anything before it freaks me out. Is that equivalent, or does that comma serve an important role?) $\endgroup$ – ibeatty Mar 16 '15 at 21:01
  • $\begingroup$ It's an undocumented form of Function (null first arg.). IIRC, it used to require null (or just comma), might have changed in later versions...Yep, just checked, w/o comma is fine. $\endgroup$ – ciao Mar 16 '15 at 21:03
  • $\begingroup$ Thanks much for the accept - do note, Simon's answer is every bit as good (the body is just a placeholder that gets rewritten to a function of the result of your function (g in his example)). Deserves upvotes... $\endgroup$ – ciao Mar 16 '15 at 22:15
  • $\begingroup$ I think the Null argument is required only if you want to use the third argument (Attributes). $\endgroup$ – Simon Woods Mar 16 '15 at 22:38
13
$\begingroup$

You may already have discovered that something like g[#]& doesn't work - this is because Function has the HoldAll Attribute, so its argument (g[#] in this case) doesn't get evaluated. The solution is to force g[#] to evaluate. Rasher showed what one way to do that, by using Evaluate, whose specific purpose is to force evaluation of arguments that would normally be held unevaluated.

Another way is to create the Function with a dummy body, then replace that body with the result of evaluating g[#]. Like this:

func = body & /. body -> g[#]
(* Piecewise[{{0, #1 < 8.}, {2.5, 8. <= #1 < 10}}, 0] & *)

func[9]
(* 2.5 *)

As is often the case in Mathematica, there are many ways to accomplish the same thing. Here are a few more.

Use With (a lexical scoping construct) to inject the evaluated expression into the Function:

func = With[{body = g[#]}, body &]

Wrap the expression to be evaluated in a Head which does not hold its arguments (such as List) and use Apply to replace that head with Function:

func = Function @@ {g[#]}

Use the DownValues of g as a replacement rule directly:

func = g[#] & /. DownValues[g]

Use Block (a dynamic scoping construct) to evaluate g[#]& in an environment where Function temporarily has no meaning and no special Attributes:

func = Block[{Function}, g[#] &]
$\endgroup$
  • $\begingroup$ I'm sorry, but I don't understand. What is "body"? Will this exact code work for any function-like rule, or only for my example g[x]? $\endgroup$ – ibeatty Mar 16 '15 at 20:47
  • $\begingroup$ Clean and cute. +1 $\endgroup$ – ciao Mar 16 '15 at 22:15
  • $\begingroup$ DownValues solution is one of kind, +1 $\endgroup$ – Algohi Mar 16 '15 at 23:50
  • $\begingroup$ Okay, thanks for elaborating. I believe I understand now. And you're right, the first thing I tried was g[#]&. $\endgroup$ – ibeatty Mar 17 '15 at 0:34

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.