0
$\begingroup$

I am almost sure that this question has been asked somewhere. I found similar ones, but I cannot find exactly what I need, which might mean that I am on the wrong track.

I search a method to pass an unevaluated function with arguments to a second function. I could achieve this with SetAttribute[,HoldAll]. However the arguments of the first function should be evaluated when I pass it, which does not seem to be the case with Hold.

To give an example: I tried things like:

mytest[test_] := Module[{}, Print[test];]
mytest1[test_] := Module[{}, myvar = 2; ReleaseHold[test];]

SetAttributes[mytest1, HoldAll]

myvar = 1
mytest1[mytest[myvar]]

This prints 2, because that is the value of myvar when ReleaseHold is called. However I want it to print 1, the value of myvar when I call mytest1. In general myvar would be an expression which may contain global variables. I do not insist on using ReleaseHold. In fact the solution should be such that mytest would be evaluated by NIntegrate. In Maple I would achieve this by enclosing the name mytest in single quotes when passing it to mytest1 which would delay evaluation by one step.

Edit

For clarification consider the following example, which is closer to the real case:

parameters = {a -> 1}

mytest[expr_, parameters_] := Module[{},
  NIntegrate[expr*a /. parameters, {var, 0, 1}]
  ]

mytest1[parameters_] := Module[{},
    globpar = 1;
    NIntegrate[mytest[globpar*var*var1, parameters], {var1, 0, 1}]
  ]

mytest1[parameters]

Mathematica returns the correct result 0.25 for this, but it issues a couple of error messages like NIntegrate::inumr: "The integrand var\ var1 has evaluated to non-numerical values for all sampling points in the region with boundaries {{0,1}}.". I want to avoid this (not by suppressing the error message!), because I want it to be fast and also the real function mytest might have a worse behavior if you insert non-numerical values. Hence I want that NIntegrate in mytest1 first inserts a numerical value for var1 and then passes the resulting expression as an argument to mytest to integrate it over var. I.e. I want that it evaluates the argument of the function first, which can however still contain names after evaluation.

$\endgroup$
5
  • $\begingroup$ myvar is a global variable. The expression mytest[myvar] is passed as that to ReleaseHold but that's after myvar=2. If you remove the SetAttributes it will work as you specify. $\endgroup$
    – Ymareth
    Feb 13, 2014 at 20:43
  • 1
    $\begingroup$ Sounds like a duplicate of this: mathematica.stackexchange.com/q/29317/12 Actually, it sounds like you are approaching a problem in the wrong way. If you describe the actual problem that prompted you to try to do this, we might be able to offer a better solution. There's no equivalent of Maple's single quote in Mathematica (well, Unevaluated comes close but it's not the same). $\endgroup$
    – Szabolcs
    Feb 13, 2014 at 21:03
  • $\begingroup$ Or perhaps you're looking for With[{myvar=1}, mytest1[mytest[myvar]]]? With can be used to inject something into a held expression. $\endgroup$
    – Szabolcs
    Feb 13, 2014 at 21:07
  • $\begingroup$ After the update to your question, can you explain why this solution isn't acceptable? This is the usual way to handle nested numerical functions (NIntegrate inside NIntegrate, FindRoot inside NMinimize, etc.) $\endgroup$
    – Szabolcs
    Feb 13, 2014 at 23:13
  • $\begingroup$ Maybe l don't understand it fully, but what l belief to understand is that it would act work to add a type 'NumericQ' to the definition of mytest, because I am passing a complete expression dependent on at least the integration variable var to that function. Maybe there is a type/pattern which tests for an expression in one variable?, but then I could wonder if it is efficient. Also the expression could in principle depend on more parameters. $\endgroup$
    – highsciguy
    Feb 14, 2014 at 9:38

1 Answer 1

1
$\begingroup$

A combination of Hold and Evaluate can achieve this: Hold[mytest[Evaluate[...],...]]. Illustrated with the example given in the question:

parameters = {a -> 1}

mytest[expr_, parameters_] := Module[{},
  (* globpar = 2; *)
  NIntegrate[expr*a /. parameters, {var, 0, 1}]
]

mytest1[parameters_] := Module[{},
  globpar = 1;
  NIntegrate[
   Hold[mytest[Evaluate[globpar*var*var1], parameters]], 
    {var1, 0, 1}]
  ]

mytest1[parameters]

Uncommenting (* globpar = 2; *) shows however that the global variable is evaluated only in the function mytest which can be avoided with one additional assignment of globpar*var*var1 to a local variable which becomes the argument of Evaluate.

$\endgroup$

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.