Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm trying to use Modules together with functions.

tmp2 = x^2 + 1; f[y_] := Module[{x = 1}, Evaluate[y tmp2]]

This works when I just have

tmp2 = x^2 + 1; Module[{x = 1}, Evaluate[tmp2]]

But f[1] outputs $1 + x^2$.

Edit: After seeing the answers I wonder how I can get something like this to work:

ClearAll[withRules]
SetAttributes[withRules, HoldAll]
withRules[rules_, expr_] := 
 Internal`InheritedBlock[{Rule, RuleDelayed}, 
  SetAttributes[{Rule, RuleDelayed}, HoldFirst];
  Unevaluated[expr] /. rules]
ClearAll[f, tmp2]
tmp2[y_] = y (x^2 + 1)
withRules[{expr -> tmp2}, f[y_] := Module[{x = 1}, expr[y]]]

Edit 2: Maybe it is better if I explain what I'd like to do.

I have a lot of calculations in terms of $k_x$, $k_y$ and $k_z$. So, those are outputted in terms of these three variables. However, sometimes I need to integrate such expressions but to do this I need to use spherical coordinates. So I set $k_x = k \sin(a) \cos(b)$ and so on and then integrate. I don't want the transformations always set because I want the other calculations to have $k_x$, $k_y$ and $k_z$ as variables, not $a$ en $b$.

share|improve this question
    
Please post a minimal example. We don't know what Trew does (nor does it seem to be relevant to the question), we don't know what result you're expecting or not expecting, the code is not indented properly and therefore hard to read. –  David Feb 19 '12 at 21:07
    
@David: Good points. I think I have reduced the problem to what my problem is... –  Jonas Teuwen Feb 19 '12 at 21:12
    
It works fine for me: imgur.com/3SatR - maybe you didn't clear some variables and have unwanted side effects? Can you reproduce the error with your example? –  David Feb 19 '12 at 21:18
    
@David: After restarting the kernel I get this: i.imgur.com/fFNw8.png. And why does it output $5$ for you? $1^2 + 1 = 2$ I'd say... –  Jonas Teuwen Feb 19 '12 at 21:23
    
Please see my edit for one possibility –  Leonid Shifrin Feb 19 '12 at 22:24
add comment

2 Answers 2

Ok, let me tell you straight away that what you are trying to do is likely to be a bad idea. Now, let me explain. The problem you face on the surface is that Evaluate is only effective at the first level inside heads which hold their arguments. Since you have SetDelayed[f[y_],Module[...]], the stuff inside Module is too deep. You need With to inject arbitrarily deep, so we try:

ClearAll[f, x];
With[{tmp = tmp2},
   f[y_] := Module[{x = 1}, y tmp]] 

However, now you face another problem: variable renaming mechanism in scoping constructs tries to protect the scoping and renames variables in part of your code:

?f
Global`f
f[y$_]:=Module[{x$=1},y$ (1+x^2)]

Here is what you can do to achieve your goal:

ClearAll[f, x];
Block[{tmp}, Unevaluated[f[y_] := Module[{x = 1}, y*tmp]] /. tmp -> tmp2]

This is explained in details here. Note however that the fact that we had to go against the system twice tells us already that this is a fragile and generally bad practice. Please see more discussion on that in the linked answer.

EDIT

In response to the edit in the question: in your case, I suggest to use Block and create a dynamic environment, where to execute the code for which you do want your transformations:

SetAttributes[withTransforms,HoldAll];
withTransforms[code_]:=
 Block[{kx=k*Sin[a]*Cos[b],ky=k*Sin[a]*Sin[b],kz=k*Cos[b]},
   code
 ]

This will allow you to selectively enable these definitions:

withTransforms[Integrate[kx^2+ky^2,{a,0,2 Pi}]]
share|improve this answer
    
I feel this is my fault, please see where this question may have come from: this comment and the preceding one. I was trying to squeeze into the comment a way to define that f function (to compute the eigenvalue) in terms of the already existing matrix. Since you are saying that this is bad practice, I felt it necessary to link to that discussion. I agree that this is a messy thing and should be avoided when possible, but occasionally it's useful. –  Szabolcs Feb 19 '12 at 21:52
    
@Szabolcs You don't sound logical now. Either you agree with my point that this is not a good practice, but then your answer (which, in fact, is not very different from mine except this point) does not reflect that, or you don't, but then why saying the question is your fault? –  Leonid Shifrin Feb 19 '12 at 21:56
    
@Szabolcs As to the occasional usefullness, I agree generally but strongly disagree for this particular class of use cases, because I think that taking the scope apart in this way is very fragile. I do sometimes use definition-time replacements, like e.g. in the lex function from this answer, but I try to avoid breaking scope, particularly nested scope, and particularly with global objects. This was also endlessly discussed on Mathgroup and lead to lots of trouble in all cases I remember. –  Leonid Shifrin Feb 19 '12 at 22:17
add comment

What you are trying to do is generate code (a function definition) programmatically.

There are several techniques to programmatically generate code. The main tool we need is injecting held expressions into other held expression. The usual way to do it is using With:

tmp2 = x^2 + 1;

With[{expr = tmp2},
 f[y_] := Module[{x = 1}, y expr]
]

Now let's check the function definition:

?f

Global`f
f[y$_]:=Module[{x$=1},y$ (1+x^2)]

You can see that Mathematica's localization mechanism has renamed x to x$ in Module, so this didn't work.

In these situations we can usually use some solution based on Replace or ReplaceAll.

It's advantageous to have this packaged up into a function. I tend to use the withRules function that I described here:

ClearAll[withRules]
SetAttributes[withRules, HoldAll]
withRules[rules_, expr_] :=
  First@PreemptProtect@Internal`InheritedBlock[
    {Rule, RuleDelayed},
    SetAttributes[{Rule, RuleDelayed}, HoldFirst];
    Hold[expr] /. rules
]

It is used in a similar way to With, but is does not localize variables like With does.

Clear[f]
withRules[{expr -> tmp2},
 f[y_] := Module[{x = 1}, y expr]
]

Checking the definition of f again we can see that now it is what we intended:

?f

Global`f
f[y_]:=Module[{x=1},y (1+x^2)]

I have asked a related question recently, and in that post you'll find a slightly more general expression injection function (inject[]), as well as several other expression injection techniques described in the answers:

share|improve this answer
    
@Mr.Wizard I don't think I should delete this time. I agree with @Leonid that often it is not good practice to do this (especially since tmp2 is global), but there are legitimate situations, and I was in fact trying to do this an hour ago in this comment –  Szabolcs Feb 19 '12 at 21:34
    
@JonasTeuwen Why won't you just use Integrate[expr /. kx -> k Sin[a] Cos[b], {a, ...}, {b, ...}] then? You should almost never need to use code generation for this kind of thing. As we say, it's like shooting at a sparrow with a cannon (and it's a cannon that can fire back this time---I have to agree with Leonid on that) –  Szabolcs Feb 19 '12 at 22:20
    
Thanks. (I had deleted my comment as I thought it would be better to just put this in my original post). I came to this "idea" while searching for "local variables mathematica". –  Jonas Teuwen Feb 19 '12 at 22:36
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.