(*^ ::[ Information = "This is a Mathematica Notebook file. It contains ASCII text, and can be transferred by email, ftp, or other text-file transfer utility. It should be read or edited using a copy of Mathematica or MathReader. If you received this as email, use your mail application or copy/paste to save everything from the line containing (*^ down to the line containing ^*) into a plain text file. On some systems you may have to give the file a name ending with ".ma" to allow Mathematica to recognize it as a Notebook. The line below identifies what version of Mathematica created this file, but it can be opened using any other version as well."; FrontEndVersion = "Macintosh Mathematica Notebook Front End Version 2.2"; MacintoshStandardFontEncoding; fontset = title, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeTitle, center, M7, bold, e8, 24, "Times"; fontset = subtitle, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeTitle, center, M7, bold, e6, 18, "Times"; fontset = subsubtitle, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeTitle, center, M7, italic, e6, 14, "Times"; fontset = section, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeSection, grayBox, M22, bold, a20, 18, "Times"; fontset = subsection, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeSection, blackBox, M19, bold, a15, 14, "Times"; fontset = subsubsection, inactive, noPageBreakBelow, nohscroll, preserveAspect, groupLikeSection, whiteBox, M18, bold, a12, 12, "Times"; fontset = text, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = smalltext, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 10, "Times"; fontset = input, noPageBreakInGroup, preserveAspect, groupLikeInput, M42, N23, bold, B65535, L-5, 12, "Courier"; fontset = output, output, inactive, noPageBreakInGroup, preserveAspect, groupLikeOutput, M42, N23, L-5, 12, "Courier"; fontset = message, inactive, noPageBreakInGroup, preserveAspect, groupLikeOutput, M42, N23, R65535, L-5, 12, "Courier"; fontset = print, inactive, noPageBreakInGroup, preserveAspect, groupLikeOutput, M42, N23, L-5, 12, "Courier"; fontset = info, inactive, noPageBreakInGroup, preserveAspect, groupLikeOutput, M42, N23, B65535, L-5, 12, "Courier"; fontset = postscript, PostScript, formatAsPostScript, output, inactive, noPageBreakInGroup, preserveAspect, groupLikeGraphics, M7, l34, w282, h287, 12, "Courier"; fontset = name, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, italic, 10, "Geneva"; fontset = header, inactive, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = leftheader, inactive, L2, 12, "Times"; fontset = footer, inactive, noKeepOnOnePage, preserveAspect, center, M7, 12, "Times"; fontset = leftfooter, inactive, L2, 12, "Times"; fontset = help, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 10, "Times"; fontset = clipboard, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = completions, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = special1, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = special2, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = special3, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = special4, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; fontset = special5, inactive, nohscroll, noKeepOnOnePage, preserveAspect, M7, 12, "Times"; paletteColors = 128; currentKernel; ] :[font = smalltext; inactive; preserveAspect] Copyright (C) 1997 Rich Neidinger, John Swallow, and Todd Will. Free for distribution to college and university instructors for personal, non-commercial use. If these notebooks are used in a course, the authors request $20 per student. :[font = title; inactive; preserveAspect] 10. Anonymous Functions :[font = smalltext; inactive; preserveAspect] Last revision: November 15 1996 :[font = text; inactive; preserveAspect] In this section we introduce anonymous functions, explore their similarity to inline functions in compiled languages, and show how anonymous functions can simplify code for certain operations. :[font = section; inactive; Cclosed; preserveAspect; startGroup] Anonymous Functions :[font = text; inactive; preserveAspect] In the previous section we considered defining functions using Modules and the colon-equals (SetDelayed) operator ":=". When we did so, we gave the new function and each of its parameters a name. This form might be called the procedural form, or long form, of a function definition. Mathematica provides another form which eliminates the need to name the function or its parameters; instead, the expression itself, without names, "is" the function definition, hence the term "anonymous function". :[font = text; inactive; preserveAspect] Why would we want to use expressions which represent functions instead of simply defining them with names? There are several reasons. First, we may only need to use the function one particular time, in which case we need not name it to use it again. Second, the representations of "anonymous functions" provide a simple shortcut to defining functions, and while some anonymous functions are extremely difficult to read, the simpler ones are just as easy to read as the equivalent named functions defined using colon-equals. Finally, we introduce "anonymous functions" because they have a cousin in many compiled languages, which we describe as follows. ;[s] 5:0,0;43,1;52,0;80,1;89,0;657,-1; 2:3,13,9,Times,0,12,0,0,0;2,13,9,Times,2,12,0,0,0; :[font = subsection; inactive; Cclosed; preserveAspect; startGroup] Inline functions :[font = text; inactive; preserveAspect] Computers do not actually execute the source code written in any language; in one way or another, the source code must be converted into machine code---the only code the computer understands---and then executed. In interpreted languages such as Mathematica, this conversion happens "on-the-fly" in the sense that only when we ask to execute a cell (and every time we ask to execute a cell) is the code converted. In contrast, for compiled languages such as C, Fortran, or Pascal, the source code is passed through a compiler which performs the conversion, leaving the final machine code in a file which can be executed repeatedly without reconversion. ;[s] 7:0,0;137,1;149,0;354,1;359,0;517,1;525,0;655,-1; 2:4,13,9,Times,0,12,0,0,0;3,13,9,Times,2,12,0,0,0; :[font = text; inactive; preserveAspect] During the compilation process, the compiler of a standard computer language reads the source code several times, collecting the names of variables, assigning them storage locations, checking for errors, and so on. Typically one "pass" over the source code is devoted to expanding out so-called "inline functions", and these are cousins to Mathematica's "anonymous functions". Let's examine the difference between the way an inline function and a normal function is embedded in machine code by looking at how a compiler might convert some Mathematica code into a machine language. (Of course, this machine language is intended to be representative only; no computer exists which executes these machine instructions.) :[font = text; inactive; preserveAspect] Suppose the code is the following: :[font = text; inactive; preserveAspect] f[x_] := x^2 + x + 5; a = f[10]+f[20]+f[30]; :[font = text; inactive; preserveAspect] If "f[ ]" were not declared inline, then the machine code might look like this: :[font = text; inactive; preserveAspect] (1) Copy "10" to "x" inside function "f" (2) Go to function "f" (step 13), execute its instructions, and return (3) Copy result of function "f" to temporary variable "t" (4) Copy "20" to "x" inside function "f" (5) Go to function "f" (step 13), execute its instructions, and return (6) Copy result of function "f" to temporary variable "u" (7) Copy "30" to "x" inside function "f" (8) Go to function "f" (step 13), execute its instructions and return (9) Copy result of function "f" to variable "a" (10) Add "a" and "u" and store the result in "a" (11) Add "a" and "t" and store the result in "a" (12) Stop (13) [Beginning of function "f"] Square "x" and store in temporary variable "v" (14) Add "v" and "x" and store the result in temporary variable "v" (15) Add "v" and "5" and store the result in our result variable "result" (16) Return to original ("calling") instruction :[font = text; inactive; preserveAspect] Note that the main code (steps 1--12) jumps down to step 13 three separate times to execute the function, and that each of these times it copies beforehand a value into the variable "x" of the function and, after the function executes, copies the result of "f" back to a variable. These jumps, together with the copy operations before and after the jumps, are called function calls. ;[s] 3:0,0;369,1;383,0;387,-1; 2:2,13,9,Times,0,12,0,0,0;1,13,9,Times,2,12,0,0,0; :[font = text; inactive; preserveAspect] Now suppose "f[ ]" were declared inline. Then the machine code might instead look like this: :[font = text; inactive; preserveAspect] (1) Square "10" and store value in temporary variable "t" (2) Add "t" and "10" and store the result in "t" (3) Add "t" and "5" and store the result in "t" (4) Square "20" and store value in temporary variable "u" (5) Add "u" and "20" and store the result in "u" (6) Add "u" and "5" and store the result in "u" (7) Square "30" and store value in temporary variable "v" (8) Add "v" and "30" and store the result in "v" (9) Add "v" and "5" and store the result in "v" (10) Add "u" and "v" and store the result in "a" (11) Add "t" and "a" and store the result in "a" (13) Stop :[font = text; inactive; preserveAspect] Here we find instead no function calls; instead the instructions of the function are embedded in the main code, one set (1-3, 4-6, 7-9) for each reference ("f[10]", "f[20]", "f[30]") of the function. ;[s] 3:0,0;21,1;24,0;200,-1; 2:2,13,9,Times,0,12,0,0,0;1,13,9,Times,2,12,0,0,0; :[font = text; inactive; preserveAspect] What tradeoffs are present in the choice to use inline or normal functions? First and foremost, programs using inline functions execute faster. This increase in speed is due to the fact that the program does not have to spend time copying values back and forth between the main code and the function's own separate variables. The drawback is that inline functions frequently require more lines of code---more memory devoted to the program itself. We do not see this drawback in the case above, since the function itself needed only a few instructions, but suppose the function needed 200 machine instructions to accomplish its task and let's count how many machine instructions would be necessary to cover each of the three references to the function. We would need a few instructions---a few copies, and the jump instruction---for each reference of the function, together with one instance of all of the instructions for the function, placed at the end. At three instructions per function call, plus 200 instructions for the function at the end, we find we need 209 instructions. However, with inline functions, each of the 200 instructions would need to appear inside the main code every time the function were referenced, yielding fully 600 instructions devoted to the function references. Thus we have a tradeoff between speed of execution of the program and memory requirements for the program. :[font = text; inactive; preserveAspect; endGroup] To summarize, an inline function is a function which is not implemented in the standard fashion, using one set of instructions for the function, together with one function call for each reference. Instead, when the compiler finds an inline function referenced in the source code, it immediately inserts the instructions of the function into the program itself---hence the term "inline"---and does not insert a "function call". ;[s] 3:0,0;17,1;32,0;430,-1; 2:2,13,9,Times,0,12,0,0,0;1,13,9,Times,2,12,0,0,0; :[font = subsection; inactive; Cclosed; preserveAspect; startGroup] Syntax of Anonymous Functions :[font = text; inactive; preserveAspect] Since anonymous functions have no name, we don't, in fact, declare or define them. Instead, we "express" them. To express an anonymous function, think of it in its normal "defined" form and replace every occurrence of the name of the parameter with "#" (if there's only one parameter), or replace every occurrence of the first named parameter by "#1", every occurrence of the second named parameter by "#2", and so on. Then eliminate the left-hand side of the colon-equals sign and the colon-equals symbol itself, enclose the remaining expression in parentheses (to be safe), and append the "anonymous function operator" "&" to the expression. :[font = text; inactive; preserveAspect] For example, let's look at how we might convert the our squaring function into an anonymous function. Here's the squaring function, as defined before: :[font = input; preserveAspect] square[x_] := x^2; :[font = text; inactive; preserveAspect] We note that there is only one parameter. Hence we replace every occurrence of "x" by "#", to get "square[#_] := #^2"; then we eliminate the colon-equals sign and all that precedes it, to get "#^2"; then we enclose the expression in parentheses and append a "&", resulting in :[font = input; preserveAspect] (#^2)& :[font = text; inactive; preserveAspect] Yes, the anonymous function is somewhat harder to read. For an example of a case where using an anonymous function simplifies code, consider the following situation. We wish to iterate the function "Exp[-x]" over and over again beginning with the value 1. One solution is the following: :[font = input; preserveAspect] newExp[x_] := Exp[-x]; Nest[newExp,1.,100] :[font = text; inactive; preserveAspect] It is irritating that we have to go to the trouble of defining a separate function in order to use such a simple operation. The anonymous function solution is much simpler: :[font = input; preserveAspect] Nest[Exp[-#]&,1.,100] :[font = text; inactive; preserveAspect] (Note we didn't need the parentheses this time.) :[font = text; inactive; preserveAspect; endGroup] What follows are several examples of bottom-up programming, coupled with a judicious use of anonymous functions. :[font = subsection; inactive; Cclosed; preserveAspect; startGroup] Example 1: Replication :[font = text; inactive; preserveAspect] By now you should appreciate the idea of building up a function slowly, starting with the simple things and gradually adding more layers. Let's try that idea again now. We want to write a function called "replicate[ ]" which should take a list of integers and return a list where each number n (in the list) has been replicated n times. For example, "replicate[{3,2,4,2}]" should return "{3,3,3,2,2,4,4,4,4,2,2}". As a first simple step, how can we replicate a single number, say 3? We'll begin with the following: :[font = input; preserveAspect] Clear[f] f[n_]:=Table[n,{n}] f[3] :[font = text; inactive; preserveAspect] Now we want to replicate each number in the list {3,2,4,2}, so we'll map "f[ ]" onto the list. :[font = input; preserveAspect] Map[f,{3,2,4,2}] :[font = text; inactive; preserveAspect] Now all we need to do is use "Flatten[ ]" on this list. :[font = text; inactive; preserveAspect] (It always helps to remember that, when trying to write a new function in Mathematica, we should do three things: (1) clear any old definition; (2) make the new definition; and (3) test the new definition.) :[font = input; preserveAspect] Clear[replicate] replicate[list_]:=Flatten[ Map[f,list] ] replicate[{3,2,4,2}] :[font = text; inactive; preserveAspect] One problem with our "replicate[ ]" function is that it relies on the function "f[ ]" which we defined earlier. By now you've probably experienced the problem of trying to execute a function that relied on something you'd not yet defined. (Imagine trying to find "roster[[4]]" without having first executed "roster={....}". ) But even if we do remember to define "f[ ]", before trying "replicate[ ]", we have to remember not to redefine "f" as something else in a different problem. For example, if the next problem in this lab asked us to plot "f(x)=x+Sin[x]" we might casually enter: :[font = input; preserveAspect] Clear[f] f[x_]= x+Sin[x] Plot[f[x],{x,-2Pi,2Pi}] :[font = text; inactive; preserveAspect] Now "replicate[ ]" will still run, but it will not run correctly. :[font = input; preserveAspect] replicate[{3,2,4,2}] :[font = text; inactive; preserveAspect] Clearly using "f[ ]" in the definition for "replicate[ ]" is a very dangerous method. We now know two solutions to this problem: (1) use a Module: create a function "f[ ]" inside a Module that only the function "replicate[ ]" knows about, and (2) use an anonymous function: use the function "f[ ]" without ever giving it a name. :[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup] Module Solution :[font = input; preserveAspect] Clear[replicate,f] replicate[list_]:= Module[{f}, f[n_]:=Table[n,{n}]; Flatten[ Map[f, list] ] ] replicate[{1,2,3}] :[font = text; inactive; preserveAspect] One advantage of the "Module[ ]" command is that the function "f" is defined in the same place as "replicate[ ]", so we don't have to worry about forgetting to execute the definition for "f[ ]" before using "replicate[ ]". The great advantage of using Module, however, is that our definition of "f[ ]" doesn't show up outside of the "replicate[ ]" function. Let's check. :[font = input; preserveAspect] ?f :[font = text; inactive; preserveAspect] We can now use "f[ ]" elsewhere, as in :[font = input; preserveAspect] f[x_]= x+Sin[x] :[font = text; inactive; preserveAspect] and "replicate[ ]" still works just fine. :[font = input; preserveAspect; endGroup] replicate[{3,2}] :[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup] Anonymous Function Solution :[font = text; inactive; preserveAspect] We want to replace the "f[ ]" we defined up above with an anonymous function. Recall that we had defined "f[n_]:=Table[ n, {n}]". Following our rules for converting the definition into an expression with no named parameters, we get "Table[ #, {#}]". So the anonymous function is "Table[ #,{#}]&" or, more safely, "(Table[ #,{#}])&". :[font = input; preserveAspect] Table[#,{#}]& [3] :[font = text; inactive; preserveAspect] Note that the 3 gets substituted into each of the #'s, and the resulting "Table[3,{3}]" is executed. Now we can map this anonymous function onto a list just as we did the named function "f[ ]". ;[s] 3:0,0;38,1;42,0;195,-1; 2:2,13,9,Times,0,12,0,0,0;1,13,9,Times,2,12,0,0,0; :[font = input; preserveAspect] Clear[replicate] replicate[list_]:= Flatten[ Map[ Table[#,{#}]&, list] ] replicate[{1,2,3}] :[font = text; inactive; preserveAspect] Using an anonymous function gave us a shorter segment of code than using a Module, and this segment will also run a little bit faster. To see this, let's time how long it takes for each to run 10 times: :[font = input; preserveAspect] Clear[replicate1,replicate2] replicate1[list_]:= Module[{f}, f[n_]:=Table[n,{n}]; Flatten[ Map[f, list] ] ]; replicate2[list_]:= Flatten[ Map[ Table[#,{#}]&, list] ]; :[font = input; preserveAspect] Timing[Do[replicate1[{1,2,3}],{10}]] :[font = input; preserveAspect; endGroup; endGroup] Timing[Do[replicate2[{1,2,3}],{10}]] :[font = subsection; inactive; Cclosed; preserveAspect; startGroup] Example 2: Selecting some {x,y} pairs (First, Last, Select) :[font = text; inactive; preserveAspect] The following code gives a framed plot of 50 random points in the unit square in the first quadrant. :[font = input; preserveAspect] pairs=Table[{Random[],Random[]},{50}]; ListPlot[pairs, Frame->True, AspectRatio->Automatic, PlotRange->{{0,1},{0,1}}]; :[font = text; inactive; preserveAspect] We would like to write a function "aboveLine[ ]" that will select from the points above those that are above the line y=x. In other words, we would like to decide, for each point, whether the "y" value is greater than the "x" value---this is what "above the line" means mathematically---and then choose only those points from the first random list. We'll use some functions "First[ ]" and "Last[ ]" which operate on lists as might be expected: :[font = input; preserveAspect] aboveLineOne[point_]:= Last[point]>First[point] :[font = input; preserveAspect] aboveLineOne[{.2,.4}] :[font = input; preserveAspect] aboveLineOne[{.6,.2}] :[font = text; inactive; preserveAspect] It looks as if we've solved the problem of deciding whether a point is above the line y=x, but rather than defining the function out in the open, let's place this function inside a Module. Clear the current definition of "aboveLineOne[ ]" before starting. :[font = input; preserveAspect] Clear[aboveLineOne] :[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup] Module Solution :[font = text; inactive; preserveAspect] We will use the "Select[ ]" function. "Select[ ]" takes two arguments, the first a list from which we want to extract certain elements, the second a function which, for each element of the list, will give a True or False answer to whether we want the element. :[font = input; preserveAspect] Clear[aboveLine] aboveLine[points_]:= Module[{aboveLineOne}, aboveLineOne[point_]:= Last[point]>First[point]; Select[points, aboveLineOne] ] abovePts=aboveLine[pairs]; :[font = text; inactive; preserveAspect] Let's plot these points and see whether our code is correct. :[font = input; preserveAspect] ListPlot[abovePts, Frame->True, PlotRange->{{0,1},{0,1}}, Axes->None, AspectRatio->Automatic]; :[font = text; inactive; preserveAspect; endGroup] All the points do seem to be above y=x. :[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup] Anonymous Function Solution :[font = text; inactive; preserveAspect] We want an anonymous version of the function: "aboveLineOne[point_] := Last[point] > First[point]." Now "point" is the only parameter, so we use "#" in place of it, which yields an expressed anonymous function "Last[#]>First[#]&". Let's try it out: :[font = input; preserveAspect] Last[#]>First[#]& [{3,4}] :[font = text; inactive; preserveAspect] Now we use the function to select the points above the line. :[font = input; preserveAspect] Clear[aboveLine] aboveLine[points_]:= Select[ points, Last[#]>First[#]& ] abovePts=aboveLine[pairs]; :[font = input; preserveAspect; endGroup; endGroup] ListPlot[abovePts, Frame->True, PlotRange->{{0,1},{0,1}}, Axes->None, AspectRatio->Automatic]; :[font = subsection; inactive; Cclosed; preserveAspect; startGroup] Example 3: Selecting multiples of k from a list (Q functions) :[font = text; inactive; preserveAspect] Suppose that we want to know which of the following integers are multiples of some integer we specify, such as, say, 3. :[font = input; preserveAspect] numbers={23,5,3,345,67,345,245,4,2,2,5,36,3,42,2,436} :[font = text; inactive; preserveAspect] How do we know if an Integer is a multiple of another Integer? We might ask a simpler question: how do we know if a value is an Integer? Can we ask Mathematica? Yes. There are boolean functions "NumberQ", "IntegerQ", "EvenQ", "OddQ", and even "PrimeQ", which simply return True or False depending on the value of the argument. The "Q" in the names is a shorthand for the word "Query". Let's try a few: :[font = input; preserveAspect] IntegerQ[3.5] :[font = input; preserveAspect] NumberQ[2/3] :[font = input; preserveAspect] OddQ[2] :[font = input; preserveAspect] PrimeQ[373587883] :[font = text; inactive; preserveAspect] We return to our original question in light of these boolean functions. To know whether or not one Integer is a multiple of another, we divide and ask whether the result is an Integer. :[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup] Module Solution :[font = text; inactive; preserveAspect] We incorporate "multK[ ]" into the definition of "multiples[ ]", using the value of "k" which is an argument of "multiples[ ]": :[font = input; preserveAspect; endGroup] Clear[multiples,multK] multiples[numbers_,k_]:= Module[{multK}, multK[x_]:=IntegerQ[x/k]; Select[numbers, multK ] ] multiples[numbers,3] :[font = subsubsection; inactive; Cclosed; preserveAspect; startGroup] Anonymous Function Solution :[font = text; inactive; preserveAspect] We replace "multK[ ]" with the anonymous (nameless) equivalent, "IntegerQ[ #/k] &": :[font = input; preserveAspect] Clear[multiples,multK] multiples[numbers_,k_]:= Select[numbers,IntegerQ[#/k]&] multiples[numbers,3] :[font = text; inactive; preserveAspect; endGroup; endGroup] Here the anonymous function has only one argument from elements in the list "numbers"; "k" appears as an argument to the function "multiples". :[font = subsection; inactive; Cclosed; preserveAspect; startGroup] Use of Anonymous Functions :[font = text; inactive; preserveAspect; endGroup; endGroup] The examples above suggest that anonymous functions are best employed when (a) the operation(s) to be performed are simply expressed, (b) the operations use relatively few parameters, and (c) when we need to use a function which requires, as one of its parameters, the name of a function, in which place we may place the anonymous function. Particularly appropriate functions which take functions as parameters are "Select[ ]", "Map[ ]", and "Apply[ ]". ^*)