13
$\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$
1
  • $\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, 2015 at 20:46

2 Answers 2

12
$\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$
4
  • $\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, 2015 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, 2015 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, 2015 at 22:15
  • $\begingroup$ I think the Null argument is required only if you want to use the third argument (Attributes). $\endgroup$ Mar 16, 2015 at 22:38
14
$\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$
4
  • $\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, 2015 at 20:47
  • $\begingroup$ Clean and cute. +1 $\endgroup$
    – ciao
    Mar 16, 2015 at 22:15
  • $\begingroup$ DownValues solution is one of kind, +1 $\endgroup$ Mar 16, 2015 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, 2015 at 0:34

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.