Group Abstract Group Abstract

Message Boards Message Boards

1
|
9.2K Views
|
11 Replies
|
10 Total Likes
View groups...
Share
Share this post:

How to define a function dynamically?

Posted 4 years ago

I want do define a (local or global) function with a dynamic name, arguments and body. The name comes from a string funcName, the arguments from a list args and the body from an expression body.

I.e.: If

funcName = "funcX"; args = {x,y}; body = (x+y)^2; 

are given, I want do define a function

funcX[x_ , y_ ] := (x+y)^2;

I tried many things and read a lot of docs to achieve that, but I could not succeed. Can anybody help me?

POSTED BY: Werner Geiger
11 Replies

Here is a pretty concise solution using Inactive:

Activate[Inactive[SetDelayed][ToExpression[funcName]@@(Pattern[#,_]&/@args),body]]

and another using With:

With[{funcName=ToExpression[funcName],args=Pattern[#,_]&/@args,body=body},
    Evaluate[funcName@@args]:=body
]
Posted 4 years ago
POSTED BY: Werner Geiger
POSTED BY: Neil Singer
Posted 4 years ago
POSTED BY: Werner Geiger

Ok, Werner,

You sparked my interest! Here is what you asked for:

makefun[name_String, args_List, body_] := 
 Module[{myfun}, 
  myfun[(Map[Pattern[#, Blank[]] &, args]) /. List -> Sequence] := 
   Evaluate[body]; Clear[name]; 
  DownValues[name] = DownValues[myfun] /. myfun -> Symbol[name];]    

nargs = {x, y};
nbody = (x + y)^2;


makefun["funcX", nargs, nbody]

This will construct a "function" that is identical to the definition you get with

funcX[x_,y_]:= (x+y)^2

Regards,

Neil

POSTED BY: Neil Singer

Werner,

You can’t use setdelayed because we are intentionally altering the default evaluation order to get your function defined.

Other than the internal representation, the pure function and the delayed function behave identically. The only difference is the SetDelayed function undergoes an extra pattern match evaluation before it’s used.

In the documentation it states that these are equivalent.see Pure Functions Tutorial

Why is this subtle difference a problem in your application?

Regards

Neil

POSTED BY: Neil Singer
Posted 4 years ago
POSTED BY: Werner Geiger

This approach is also considerably faster than trying to construct a string and turning it into an expression (about 30 times faster).

POSTED BY: Neil Singer

Werner,

You can simplify things by using Function[]. I test if it is already defined, if so, I remove it so this code can be rerun without errors:

In[27]:= funcName = "funcX";
args = {x, y};
body = (x + y)^2;
If[NameQ[funcName], Remove[Evaluate[funcName]]];
Evaluate[Symbol[funcName]] = 
  Function[Evaluate[args], Evaluate[body]];
funcX[3, 2]

Out[33]= 25

Regards,

Neil

POSTED BY: Neil Singer
Posted 4 years ago

Hi Werner,

Here is a way to do it if args and body are converted to strings. Quite clumsy, not very generic, and probably easy to break.

ClearAll[makeFunction, funcX, x, y]

makeFunction[name_String, args_String, body_String] := ToExpression[name <> "[" <> args <> "]:= " <> body]

name = "funcX"; args = {x, y}; body = (x + y)^2;

argsString = ToString[#] <> "_" & /@ args // StringRiffle[#, ", "] &;
bodyString = TextString@body;

makeFunction[name, argsString, bodyString]

funcX[1, 2]
(* 9 *)
POSTED BY: Rohit Namjoshi
Posted 4 years ago
POSTED BY: Werner Geiger
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard