# Turn expression into function

I'm new to Mathematica and I spent the last hour trying to make the expression

expression =
3 + 2 cos[t] + 3 cos[2t] + 5 cos[3t] + 7 cos[4t] + 9 sin[t] +  4 sin[3t] + 5 sin[4t]


into a function of t. I tried

f[t_] := expression


but it didn't work.

-
let it be expression[t_]..1 hour is not enough for trials. You can always spend more time. – Rorschach Sep 9 '13 at 17:48
@Blackbird I find your comment very offensive. Who are you to tell people how much time they should or shouldn't spend doing something prior to asking for help? In my honest opinion Beni could have posted this question immediately after discovering the issue and it would be just fine. The issue arises due to him not being familiar with the evaluation principle of Mathematica, so it would most likely be a huge waste of time trying to brute force your way through it rather than simply asking others more experienced for help. – jVincent Sep 10 '13 at 9:46
@jVincent and others : Apologies if I offended someone but all I was saying is that sometimes putting in little more effort helps us know how close we were to giving up and upgrades one's stamina to fight with problem. I will take your point in consideration and will avoid any such unasked suggestion in future. – Rorschach Sep 10 '13 at 9:59
@Beni I notice that you have not Accepted an answer. Are all the ones given inadequate? If so, how, that I may improve mine. – Mr.Wizard Sep 18 '13 at 18:13

Evaluate is your friend

expression =
3 + 2 Cos[t] + 3 Cos[2 t] + 5 Cos[3 t] + 7 Cos[4 t] + 9 Sin[t] +
4 Sin[3 t] + 5 Sin[4 t];
f[t_] := Evaluate[expression];
f[0]


20

Edit: This is the same as

f[t_] = expression;

-
You can do f[t_] = expression which is the same thing. := delays evaluation because it has the HoldAll attribute, and Evaluate takes precedence over that, so in total it's just = – ssch Sep 9 '13 at 18:10
@ssch Oh yes, of course! – ybeltukov Sep 9 '13 at 18:15
+1. Just to mention one subtlety: the form lhs:=Evaluate[rhs] is, strictly speaking, not fully equivalent to lhs = rhs, in terms of how the rules are stored internally. In most cases this does not matter, but in some it does. For example: a := Evaluate[Range[10]] . Trying the Part assignment will result in an error. Try e.g. a[[2]] = 1. This won't happen for direct assignment. – Leonid Shifrin Sep 18 '13 at 10:13

First, note that sin and cos are not built-in functions; I shall use Sin and Cos.

Please see: Scoping in assigning a derivative

Typically you do not want to make a definition for a parameter t without protecting t on the RHS. That is to say, using Evaluate or f[t] = can leave t to evaluate to its present global value.

If you define expression with := you will make sure t remains unevaluated there as well.

t = "Fail!";

expression :=
3 + 2 Cos[t] + 3 Cos[2 t] + 5 Cos[3 t] + 7 Cos[4 t] + 9 Sin[t] + 4 Sin[3 t] + 5 Sin[4 t]

Block[{t},
f[t_] = expression;
]

f[0.7]

6.84554


The method above is automated in the abstraction localSet defined here:

-

Using Evaluate to make a function is not a robust solution. A true function is one which takes all its input from its arguments and return its result from its last return value and has no side effects out of this.

Here is an example why Evaluate does not make f[t] a true function

expression = Cos[t] + globalX;
globalX = 1;
f[t_] := Evaluate[expression];


In the above, f[t] took part of its input (the t only) via the argument, but the other part (x) was accessed by using a global variable. Accessing global variables from inside a function is not a good way to do things (tm).

It is better to do it the good old fashioned way, and put the body of the function inside the function, and pass it all its input via arguments

f[t_, x_] := Cos[t] + x


The difference is important. If one writes some Module and uses symbols not passed via arguments and also not local to the module, then the notebook interface will show this symbol with different color. This can be important in telling one something is wrong. This becomes more important when working with lots of functions and more complex program. By Evaluating an external expression, one does not have the advantage of this check.

Compare the color of x used by the function in these 4 cases:

and

and

a black colored x will immediately tell one they are accessing a global x (a symbol with different context at least), and to correct this. The third and fourth examples above are true functions, while the first two are not.

-
The reason I did it like I presented is that I need to construct trigonometric polynomials starting from coefficients... – Beni Bogosel Sep 9 '13 at 19:42
"A true function is one.... " You mean a pure function. Functions in Mathematica do not have to be pure, and as such you can justifiably use Evaluate, however as you note it will not be pure (like a ton of other Mathematica functions are not mind you). But describing it as not a "true" function could cause confusion. Besides this point, purity in Mathematica is a much more complicated issue than in other languages, and an argument could be made that no functions are pure. Even f[x_]:=x^2 will depend on state and can have side effects. – jVincent Sep 10 '13 at 9:51
@jVincent no, I meant true function, not pure. true function in the mathematical sense. it only acts on its input via arguments, and has local variables and has no side effects other than its return value. A true function does not even allow passing argument by reference. Ada functions used to be true, until Ada 2012 where they relaxed allowing a function to be passed an argument by reference (called in-out). Many in Matematica write functions that are not true functions, where some of its input is passed by arguments and some of its input is global. – Nasser Sep 10 '13 at 16:10
....on the side effect, it is done by documentation. Each function should document any side effects it makes. Things like creating a file, or updating a file, and such are considered a side-effect and can't be prevented by the language. But should be documented in the function header, so someone reading this function later on, can see right away what are its side-effects. – Nasser Sep 10 '13 at 16:16
"in the mathematical sense" Then you should add this. You where talking about Mathematica, which is a programming language, thus the correct definition of function is the contextual one. It's like arguing that a child's imaginary giraffe is not "truly" imaginary because you can't square it to yield a negative giraffe. While the names used overlap, the definitions are different, and neither is universally "true". – jVincent Sep 10 '13 at 17:06

While other answers are valid, I believe you could just use something as straightforward as

f = Function[t, Evaluate@expression]

Let's see how it works:

In[1]:= expression = 3 + 2 cos[t] + 9 sin[t]
+ 3 cos[2t]
+ 5 cos[3t] + 4 sin[3t]
+ 7 cos[4t] + 5 sin[4t];
In[2]:= ClearAll[f]

In[3]:= f = Function[t, Evaluate@expression]
Out[3]= Function[t, 3 + 2 cos[t] + 9 sin[t]
+ 3 cos[2t]
+ 5 cos[3t] + 4 sin[3t]
+ 7 cos[4t] + 5 sin[4t]]


Then,

In[4]:= f[0]


evaluates:

Out[4]= 3 + 17 cos[0] + 18 sin[0]


(Mathematica only has definitions for capitalized Cos and Sin, that's why no more simplifications for your expression are provided.)

You may skip the rest of the answer if this solution is enough for you, and you are not interested in Mathematica subtleties.

However, there is a subtle aspect that may cause unexpected problems in the future. In[3] would modify the “own values” of symbol f:

In[5]:= OwnValues[f]
Out[5]= {HoldPattern[f] :>
Function[t,
3 + 2 cos[t] + 9 sin[t]
+ 3 cos[2t]
+ 5 cos[3t] + 4 sin[3t]
+ 7 cos[4t] + 5 sin[4t]]}


and if you try to add some modifications to your definition then, you could unexpectedly bump into error:

In[6]:= f[t_, shift_] := shift + f[t]


(Check out the Out[5] error message if you want.) Definitions like the one in In[5] deal with “down values” of f, contrary to “own values”.

You could use a bit more elaborate mechanism for assigning DownValues, in case you plan to use In[6]-like definitions for f extensively in the future:

In[7]:= nameToPattern = # :> Pattern[#, Blank[]] &;

In[8]:= defineWithExplicitArguments[listOfArgs_List, f_, expr_] :=
With[{listOfPatterns = listOfArgs /. nameToPattern /@ listOfArgs}, (
DownValues@f = DeleteCases[DownValues@f, _[_[_@@listOfPatterns], _], 1];
Evaluate[f@@listOfPatterns] := expr)]

In[9]:= defineWithExplicitArguments[singleArgument_, f_, expr_] :=
With[{pattern = singleArgument /. nameToPattern@singleArgument}, (
DownValues@f = DeleteCases[DownValues@f, _[_[_@pattern], _], 1];
Evaluate[f@pattern] := expr)]


Now, let's remove all definitions for f

In[10]:= ClearAll[f]


and we're free to use defineWithExplicitArguments for assigning “down values” to it:

In[11]:= defineWithExplicitArguments[t, f, expression]

In[12]:= f[0]
Out[12]= 3 + 17 cos[0] + 18 sin[0]


In[13]:= f[t_, shift_] := shift + f[t]

In[14]:= f[0, -3]
Out[14]= 17 cos[0] + 18 sin[0]


By the way, the In[13] definition could be added by means of defineWithExplicitArguments, as well. Let's check it:

In[15]:= f[t_, shift_] =.


Here, we redefined “two-arguments version” of f, and it does not calculate the shifted wave anymore:

In[16]:= f[0, -3]
Out[16]= f[0, -3]


Then,

In[17]:= defineWithExplicitArguments[{t, shift}, f, expression + shift]


makes it work again:

In[18]:= f[0, -3]
Out[18]= 17 cos[0] + 18 sin[0]

-
Note that at least your first form Function[t, Evaluate@expression] does not protect t from a global value, should one desire that. – Mr.Wizard Sep 10 '13 at 13:26
@Mr.Wizard I'm sorry, but I don't really understand the concept of “protecting from a global value”. :-/ I assume everything to be evaluated in a single context and could only add this note to the answer. For sure, almost anyone's edit regarding global vs local issues would be more reliable than mine. – Akater Sep 10 '13 at 13:47