2
$\begingroup$

I've been mucking around with passing functions as arguments to other functions and via trial and error seem to have something that works. I was wondering if someone could have a quick look at some simple example code and let me know if this method is sound or if there are some things that I am overlooking.

Cheers...

Clear[mother];
mother[] :=
 Module[{f},
  f[x_, y_, z_] := x + y + z;
  child[f]
]

Clear[child];
child[functionArgument_] :=
  Module[{},
   functionArgument[1, 2, 3]
]
$\endgroup$
4
$\begingroup$

You did not explain (at least to my satisfaction) what this code it supposed to do therefore is hard to give a rigorous answer, but I will attempt to cover multiple issues.

First a note: Module[{}, . . . ] is arguably a purposeless construct, one I have no use for and which I remove with every opportunity I get. However at least one very experienced user likes this construct as a kind of tag signifying code with side-effects, though personally I find the idea of adding superfluous code as a form of comment disturbing.

Interpretation

If I understand your question it can be restated as the idea of using this to generate a function:

make[] :=
  With[{r = RandomInteger[99]},
    Module[{f}, f[x_, y_, z_] := x + y + z + r; f]
  ]

make[]
f$615
Definition[ f$615 ]
Attributes[f$615] = {Temporary}

f$615[x$_, y$_, z$_] := x$ + y$ + z$ + 92

If so the answer is yes, this is a common and effective method to create functions.

  • The Symbol produced (here f$691) is unique within the kernel session and may be freely reused during that session, but saving and reloading this definition in another session could cause a collision.

Alternatives

There are at least two alternatives to the pattern shown above. The first uses Function:

make2[] := With[{r = RandomInteger[99]}, Function[{x, y, z}, x + y + z + r]]

make2[]
Function[{x$, y$, z$}, x$ + y$ + z$ + 47]

This has an advantage over the Module-defined function: the anonymous Function can be copied, modified, saved and loaded at will.

It also has an important disadvantage: Function has no pattern matching control. While you can use patterns inside the Function to perform different operations on different structures you cannot use pattern to prevent the application entirely, leaving the expression unevaluated.

The solution is a construct like the one that jVincent showed here:

Example:

SetAttributes[dFunction, HoldAll]
dFunction[pattern_, body_][arg___] /; MatchQ[{arg}, pattern] := {arg} /. pattern :> body

make3[] := With[{r = RandomInteger[99]}, dFunction[{x_?NumericQ, y_, z_}, x + y + z + r]]

fn = make3[]
dFunction[{x_?NumericQ, y_, z_}, x + y + z + 86]

Now our function will only be applied if its arguments match the given pattern:

fn["foo", 1, 2]
dFunction[{x_?NumericQ, y_, z_}, x + y + z + 86]["foo", 1, 2]
fn[Pi, 1, 2]
89 + π

Note that there is no (additional) definition to the Symbol dFunction. You can copy, modify, save and load the expression dFunction[{x_?NumericQ, y_, z_}, x + y + z + 86] just as you would a Function so long as you first load the primary definition of dFunction.

$\endgroup$
  • $\begingroup$ I was looking at your example demonstrating the memory leak but found that when I ran "Names["f$*"]" all that returned was an empty list.(?) Anyway, the extensive answer was appreciated. $\endgroup$ – Freakalien Aug 28 '14 at 13:17
  • $\begingroup$ @Freakalien Good catch. I knew that Module sometimes leaked and I saw the extra Symbols when I was preparing my answer so I included that warning. At the time I thought it must be due to interaction with child but I didn't explore it further. However a very simple Do[Module[{foo}, foo[x_] := 1; 0], {10}] also leaks and it did not used to do that. I am using version 10.0.0. I just confirmed that neither the example in this comment nor mother[] leaks in version 7. I suspect this is a bug in garbage collection; it deserves further scrutiny. $\endgroup$ – Mr.Wizard Aug 28 '14 at 15:50
  • $\begingroup$ @Freakalien Failure of garage collection in the given example is a bug in version 10.0.0. See: (58375) I shall remove those statements from my answer. $\endgroup$ – Mr.Wizard Aug 28 '14 at 16:38
  • $\begingroup$ I have V9.0.1.0 - glad I didn't upgrade! $\endgroup$ – Freakalien Aug 29 '14 at 3:11
  • $\begingroup$ @Freakalien FYI that leak has been fixed in 10.0.1. You might consider upgrading, but personally I would wait for 10.0.2, unless you have need of the new functionality. $\endgroup$ – Mr.Wizard Sep 17 '14 at 19:39

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.