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'll put the question right here, but will add some context below in case someone wonders why the heck I'm trying to do this.

Why is it that I have to do two passes to get the value of the arguments in the call to f1 below?

In[24]:= s = { 10 Cos[-Pi t], -4 Sin[0.23 t]};

In[25]:= f2[a1_, a2_, a3_] := Module[
           {a = a1, phi = a3},
           Function[
              a a2[phi #1]
           ] (* #1 is the time *)
          ]

         f1 := Function[
                 f2[#1, #2, #3]
         ]

In[27]:= l = Cases[s, amp_ trig_ [afreq_ t] -> f1[amp, trig, afreq]]
         %[[1]][.33]

Out[27]= {a$1667 Cos[phi$1667 #1] &, a$1667 Sin[phi$1667 #1] &}
         (* I expected amp and afreq to have been replaced by
            their matched values, and a numerical value here *)
Out[28]= amp Cos[0.33 afreq]

         (* It works as I (naïvely) expected when I introduce this temporary symbol, func *)
In[29]:= l = Cases[s, amp_ trig_ [afreq_ t] -> func[amp, trig, afreq]]
         % /. func -> f1
         %[[1]][.33]

Out[29]= {func[10, Cos, \[Pi]], func[-4, Sin, 0.23]}

Out[30]= {a$1668 Cos[phi$1668 #1] &, a$1669 Sin[phi$1669 #1] &}

Out[31]= 5.09041

Context: I'm a total noob to Mathematica, but I do ok with plenty of other progamming languages. This issue came up in a structural dynamics course I'm teaching, using Mathematica as a support tool. Not that it should matter here, but I'm using it to compute the dynamic response of a SDOF system to a periodic excitation.

I compute the Fourier series expansion of the forcing function, then apply a function that I've written to all terms of the expansion and then sum it all up. I have removed all of the details of this to concentrate on the essence of the problem, but I'd be more than happy to post the entire functions in case it helps.

I come from a hpc background, where we tend to overcomplicate things in search of "efficiency", bear that in mind :) The general ideal is that the response is a function of many physical parameters, and the time, but for a single term of the expansion, only the time varies and the physical parameters are fixed.

I wrote a function that takes all the physical constants and forcing terms, computes some constants as local variables inside a module, and returns a function of time using these constants.

For all terms of the expansion, however, the physical parameters are the same, just the forcing terms are different, so I wrote another function that takes the physical constants, and returns a function that takes only the forcing terms, combines them with the physical parameters and calls the function above, returning a function that depends only on time, and has all that is constant precomputed.

It's worth noticing that the variable that is not local to the module always gets substituted.

Even though the original question has been answered, I'm adding the original functions here as a justification for my roundaboutery...

fresp[F0_, w_, m_, c_, k_, trig_] :=
  Module[{phi = ArcTan[k - m w^2, c w], A = F0/Sqrt[(k - m w^2)^2 + (c w)^2]},
  Function[ t, A trig[w t - phi]]]
]

tresp[ m_, c_, k_] := Function[ 
  fresp[#1 (*F0*), #2(*w*), m, c, k, #3(*trig*)]
]

mck1 = tresp[2., 2., 3.]
mck2 = tresp[1., 1., 2.]

The idea being that each mck function would represent the response of a different physical system. I apologize if my mind has been poisoned by object orientation :)

share|improve this question

2 Answers 2

up vote 2 down vote accepted

Look at Rule (->) and RuleDelayed (:>) in the documentation.

s = {10 Cos[-Pi t], -4 Sin[0.23 t]};
f2[a1_, a2_, a3_] := 
  Module[
   {a = a1, phi = a3},
   Function[a a2[phi #1]] (*#1 is the time*)];
   f1 := Function[f2[#1, #2, #3]];

Compare:

l = Cases[s, amp_ trig_[afreq_ t] -> f1[amp, trig, afreq]];
%[[1]][.33]

amp Cos[0.33 afreq]

l = Cases[s, amp_ trig_[afreq_ t] :> f1[amp, trig, afreq]];
%[[1]][.33]

5.09041

share|improve this answer
    
Thank you! It works beuatifully. And I think I even understand why! –  Ramiro Jun 6 at 20:17
    
@Ramiro You're welcome, and welcome to the forum :) –  mfvonh Jun 6 at 21:27

Perhaps I've misunderstood something due to oversimplification of the example, but wouldn't it be better to have the precomputed constants explicitly inside the Function returned by f2 rather than using leaked Module variables (a$1667 etc) to store the values? e.g.

f2[a1_, a2_, a3_] := Module[{a = a1, phi = a3}, Function[Evaluate[a a2[phi #1]]]]

l = Cases[s, amp_ trig_[afreq_ t] :> f2[amp, trig, afreq]]
(* {10 Cos[π #1] &, -4 Sin[0.23 #1] &} *)

Through[l[0.33]]
(* {5.09041, -0.303309} *)
share|improve this answer
    
Well, it's better when you know what you're doing, which does not seem to be my case! –  Ramiro Jun 6 at 20:27
    
I was super concerned about returning local variables, because I didn't know how they were allocated. They seem to be just hidden global variables, though, no? I did it like that because I wrote the inner function first, thought it was quite perfect, and didn't think about messing it up in any way :) Your approach is a lot better, though. Many thanks. –  Ramiro Jun 6 at 20:41
    
@Ramiro, yes they're global symbols. Sometimes it's very useful to use Module symbols like that, it's not necessarily a bad thing. You just have to wary of leaking memory if the Module is evaluated many times because it will create a new unique symbol each time. In this case it was more just that there was no need to use symbolic parameters in the Function when the numerical values were already known. –  Simon Woods Jun 6 at 21:06

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.