# Compute this once, not twice

I have two questions.

So, I have a function g defined in terms of another function, f:

g[z_] := Product[f[z][[i]], { i, 1, Length [f[z] ] }];

My problem is that f[z_] takes a while to compute.

Question 1: When I call g, does it compute f twice?

Question 2: If so, is there a way to make it not do that?

Note: I simplified my code a little bit. g is actually defined in terms of two parameters, so I cannot generate a table of f and have it call the parts of the table.

• g[z_]:=Times@@f[z]
– ciao
Aug 12, 2020 at 22:13
• You cannot have a pattern object (e.g., z_) on the RHS of a function definition except in a rule. To avoid multiple evaluations use a Module, eg., g[z_] := Module[{ft = f[z]}, ...] Aug 12, 2020 at 23:17
• @BobHanlon sorry, that was a typo. Aug 12, 2020 at 23:32
• ciao gives a good example of how one can more simply write what you have shown in your answer, and it is thus likely more efficient—however, it all comes down to your f[z] definition. Are you using SetDelayed ( i.e., := ) or Set ( i.e., = )? In either case, you can use memoization to remember the values you have calculated for some f[z]. This looks something like: ...=f[z]=... where, before the ...=, you have either Set or SetDelayed and f[z_]. Aug 13, 2020 at 1:27

BobHanlon gives a good answer for 2. For question 1, Here's an easy way to test. Define f[z_] using Echo and have it return a known result. Then evaluate g[z].

In[1]:= f[z_]:=(Echo@"f[z] was called";{1,2,3});
In[2]:= g[z_]:=Product[f[z][[i]],{i,1,Length[f[z]]}];
In[3]:= g[1]

>>f[z] was called
>>f[z] was called
>>f[z] was called
f[z] was called
Out[3]= 6

• This is a neat way to profile, but couldn’t one also just use Trace? Aug 13, 2020 at 1:22
• Sure, but Trace is not always easy to follow. Echo is simple.
– Mat
Aug 13, 2020 at 1:27
• valid point. I don’t know my way around Echo & Trace is easy to apply after function definition occurs, rather than needing to insert it into the definition. Wood screw versus a machine screw maybe ;) Aug 13, 2020 at 1:30