Video and slides synchronized, mp3 and slide download available at URL http://bit.ly/NmNLvB.
David Leibs unveils some of features of Mathematica Programming Language, a functional and dynamically typed programming language. Filmed at qconsf.com.
David Leibs is a Senior Researcher at Oracle Labs. His research interests include Graphical Programming Languages, Compiler Front-ends, Domain Specific Languages, Meta-Programming, Active Libraries, and Array Programming languages. David is currently in the Virtual Machine Research Group working on a "reactive" and "lively" graphical programming interface used for technical computing.
2. Watch the video with slide
synchronization on InfoQ.com!
http://www.infoq.com/presentations
/mathematica-programminglanguage
InfoQ.com: News & Community Site
• 750,000 unique visitors/month
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• News 15-20 / week
• Articles 3-4 / week
• Presentations (videos) 12-15 / week
• Interviews 2-3 / week
• Books 1 / month
3. Presented at QCon San Francisco
www.qconsf.com
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
4. Building Material
“Lisp isn’t a language, it’s a building material”
Alan Kay
There are historically two camps in computing. One camp creates languages that focus on
making the machine more efficient. The other camp focuses on making the user more
efficient. I come from the Lisp, Smalltalk, Mathematica world. In the world of languages that
focus on the user it is sometimes difficult to separate the language from it's environment.
5. Mathematica is a power tool
•
•
•
•
•
•
Focus on making the user productive
Symbolic
Functional
Rule Based
Amazing Library
Lispy
One can program and explore while backed by the what seems to be all of mathematics. If you
need to do statistics you don't need to go outside and look for a library.
Its just a functional programming language built on top of a rule-based rewrite engine. That is
easy to say but it has profound implications. Operations are on general symbolic trees of
terms. The Mathematica expression is a very simple general framework for the representation
of both data and programs.
You start with a large general rule base and then add your own rules. The systems starts with
the wisdom of the Krell and you build out from there.
The builtins are highly optimized for efficient operations on lists and arrays that are similar to
APL. There is lots of support for functional programming idioms. There are pure anonymous
functions and efficient higher order functions like Map, Fold, Nest. All these functions apply to
general mathematica expressions and are not limited to just Lists.
The rule based style lets you easily create languages. There is even support for overloading
the already built in functions so that your new objects can be used immediately. Meta
programming is natural. If you need Objects and Classes you can build them yourself or pick
up a standard package.
6. Exploration
In[1] :=
Plot[x^2, {x, -5, 5}]
Out[1]:=
25
20
15
10
5
-4
-2
2
4
The Notebook gives you a context for exploration. You make expressions in input cells and
evaluate them. The result appears below in an output cell. It is natural to graph data and
visualize.
8. Symbolic
In[1] :=
PDF[NormalDistribution[mean, sd]]
Out[1]:=
The symbolic nature let’s you see solutions in a general way. Let’s say you forgot how to
compute the Probability Density Function for a Normal Distribution. Just give the functions
symbolic arguments instead of numeric ones.
9. Mathematica Expressions
In[1] :=
expression
Out[1]:=
result
Today we will limit ourselves to the Mathematica language. We will start with the Mathematica
expression. Like lisp, the mathematica language is homoiconic. That just means that the
language is a mathematica data structure. Unlike lisp there is just enough convenience syntax
to let you use the same infix functions with operator precedence that you learned in Algebra 1.
A user of mathematics just writes expressions and the evaluator evaluates them. We are
going to look at a sequence of expressions and talk about what the evaluator does.
I am going to pretend we are in a notebook evaluating expressions. Mathematica Notebooks
have an awesome slide show mode but we will just limit ourselves to something static.
10. Pass 1: Simple Evaluation
In[1] :=
1
Out[1]:=
1
1 is a perfectly good mathematica expression and 1 evaluates to itself.
13. Like a Calculator
In[1] :=
3+7
Out[1]:=
7
You can use Mathematica like a calculator and do arithmetic.
14. Like Algebra 1
In[1] :=
3+4*5
Out[1]:=
23
This is normal for expressions and the operator precedence is what you learned in Algebra 1.
Someone a long time ago created rules that are designed to make polynomials happy. Go
figure.
15. Function
In[1] :=
Sqrt[49]
Out[1]:=
7
A function call looks a little different because we use [ and ] instead of ( and ). In Mathematica
parens are for grouping. The Mathematica convention for built in functionality is to always use
an upper case first Character.
17. APL Like
In[1] :=
{10,20,30} + 5
Out[1]:=
{15,25,35}
Arithmetic works on Lists as well as one would expect of any reasonable language.
18. Array Programming
In[1] :=
{10,20,30} + {5,10,20}
Out[1]:=
{15,30,50}
Array Programming style algorithms is natural and one can use many of the array
programming idioms.
19. Higher Order Functions
In[1] :=
Map[Sqrt, {9,16,25,36}]
Out[1]:=
{3,4,5,6}
There are lots of functions to learn about, a lifetime of functions. There are plenty of built in
higher order functions for functional programming. The documentation for the functionality in
Mathematica is the best of anything that exists. The documentation is live Notebooks and you
can experiment with the samples.
20. Pure Functions
In[1] :=
Map[#^2&, {3,4,5,6}]
Out[1]:=
{9,16,25,36}
The #^2& is a shortcut way to make what is called a pure function. The # is an argument. You
can use #1, #2, etc. The & is a postfix way of saying Function.
21. In[1] :=
Map[ Function[{x},x^2], {3,4,5,6}]
Out[1]:=
{9,16,25,36}
Here is another way to say the same function but this time it is all spelled out and readable.
22. In[1] :=
Nest[ # * 1.06&, 100, 10]
Out[1]:=
179.085
Nest is one of my favorite higher order functions. Nest takes an initial value and an iteration
count and keeps passing the result back into the given function. Will we ever see 6% interest
again.
23. In[1] :=
Out[1]:=
NestList[ # * 1.06&, 100, 10]
{100, 106., 112.36, 119.102, 126.248, 133.823, 141.852,
150.363, 159.385, 168.948, 179.085}
NestList is wonderful, you can see all the values along the way.
We also have Fold, FoldList, FixedPoint, FixedPointList, Select.
24. In[1] :=
factorial[0] := 1;
factorial[x_] := x*factorial[x - 1];
In[2] :=
factorial[5]
Out[1]:=
120
Let's get factorial out of the way. :-) We have to do factorial.
This factorial is written is a rule oriented style. We make our cases as separate rules. This
holds the If statements at bay.
25. Pattern Variable
In[1] :=
factorial[0] := 1;
factorial[x_] := x*factorial[x - 1];
In[2] :=
factorial[5]
Out[1]:=
120
The x_ is how you specify an argument to a function. It is a pattern variable. We will come
back to patterns in the next pass. For now you can think of it like you would an argument to a
function.
27. Imperative Constructs
In[1] :=
Out[1]:=
L = {};
For[i = 0, i < 10, i++,
L = Append[L, i]];
L
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
There are the usual control constructs like If, While, For, Do, etc. This is just like a gazillion
other languages. This let’s you write in an imperative style if you must. I sometimes have to do
this when I will be translating code to Java.
28. Why isn’t Mathematica yelling at me?
In[1] :=
x
Out[1]:=
x
Ok, what about this expression? I typed a variable that has no value and I am not getting
yelled at for having done something stupid.
29. Is this Heresy?
In[1] :=
3+x
Out[1]:=
3+x
Now this is heresy! I added 3 to an uninitialized variable and didn’t get an error message.
30. In[1] :=
f[5]
Out[1]:=
f[5]
We are all used to getting yelled at when we use un-initialized variables. What's going on
here? What if I try to use a function that doesn't exist?
33. Apply is Expression Surgery
In[1] :=
Apply[factorial, %, 1]
Out[1]:=
{6,24,120}
Yes, something is going on here and it isn't a disaster, it's wonderful! I can use Apply and
change the F to our factorial at the first level of the expression. The % signifies the last result.
Yes, it's time to start over. Let's now begin pass 2. In pass 1 I was just setting up some things
for your recognition memory so I won't have to say too much later. Ok, on to pass 2 where it is
time to learn what a Mathematica expression is and we will better introduce “The Evaluator”.
34. Let’s Start Over
In[1] :=
pass 2
Out[1]:=
pass 2
Mathematica thinks this is Times[2, pass]
39. Rules Not Slots
In[1] :=
x=y
Out[1]:=
y
This expression that looks like an assignment is not assigning to a slot in memory. We create
values for Symbols be making a rule. The Symbol x now owns a value.
42. Repeated Evaluation
In[1] :=
x
Out[1]:=
1
Now the evaluator finds x has a rule that reduces x to y. The evaluator is happy to keep going
so long as it can keep reducing an expression. The Symbol y reduces to 1 and we are done.
Yes, recursion is possible.
44. Quoting
In[1] :=
Hold[1+2]
Out[1]:=
Hold[1+2]
Now Hold is very interesting! Hold is a quoting mechanism. This issue exposes a Use vs.
Mention mechanism. Languages that deal with use vs. mention are very special. This is Lispy.
Mathematica has many shades of mention. Hold is letting us tell the evaluator to not evaluate
the expression inside the Hold.
45. Canonicalization
In[1] :=
FullForm[Hold[1+2]]
Out[1]:=
Hold[Plus[1, 2]]
What we see here is the real representation of 1+2. Mathematica canonicalizes what we type
into a Mathematica expression that is in prefix form. FullForm is a way to inhibit the uncanonicalizer and lets us see inside to the true Inner Mathematica. We have uniform
Mathematica expressions all the way down.
46. Expressions
Atom
or
head[exp0, exp1, ... ,expn]
This is the simple definition of a Mathematica expression.
In general a Mathematica expression is an Atom or is a Head (which is usually a symbol)
followed by a square bracket, then a sequence of Mathematica expressions separated by
commas, and ended with a square bracket.
47. Heads
In[1] :=
Head[a + b]
Out[1]:=
Plus
The function Head let's us get the Head of an expression. Mathematica canonicalizes to a
uniform prefix style internal form.
51. Holding Evaluation
In[1] :=
Head[First[Hold[3+4]]]
Out[1]:=
Integer
Let’s try First which will grab the first element of a general Mathematica expression. Shoot,
the evaluator got it's hands on the expression once First pulled the expression out of Hold. The
Mathematica evaluator wants to evaluate everything in sight until all the pieces won't evaluate
any further.
52. Holding Evaluation
In[1] :=
Head[Unevaluated[3+4]]
Out[1]:=
Plus
Unevaluated is what we want. Unevaluated works like Hold but it isn't. Unevaluated is a one
shot thing. You use it to pass expressions without letting the evaluator evaluate them.
Unevaluated is magic and know to the evaluator. Unevaluated is another shade of mention.
You could write your own version of Hold and we will by using Mathematica but Unevaluated is
built into the evaluator.
53. Juxtaposition is Multiplication
In[1] :=
Map[Head, Unevaluated[3 + 4]]
Out[1]:=
2 Integer
Ok, what the heck happened.
Map does not have to be given a List. It works with any Head. It will map the given function
over the elements and give them back in the given Head.
54. The Evaluator
Map[Head, Unevaluated[3 + 4]]
the evaluator sees:
Map[Head,Plus[3,4]]
and computes:
Plus[Integer,Integer]
but it keeps evaluating and gives
Times[2, Integer]
The evaluator keeps going and going. Integer + Integer is 2 Integer.
55. The Evaluator
e0 [e1, e2, e3, … , en]
eval[e0] [eval[e1], eval[e2], eval[e3], …, eval[en]
...
match to rules and possibly rewrite
Ok the evaluator. I am going to call it eval. Here is what the evaluator wants to do when given
a Mathematica expression.
If eval[e0] produces something that has a rule that matches the list of evaluated arguments
then it replaces it all with that result and does it all again, and again until nothing changes.
Now, at last, the interesting part. We are ready to look at more shades of mention. We have
seen Unevaluated and Hold. The evaluator will leave an expression inside of UnEvaluated
alone and pass the expression inside on. If it can't find a rule it puts it back. This can be a little
disconcerting.
57. The symbol f has no rule
In[1] :=
f[3+4, 5+6]
Out[1]:=
f[7,11]
Like before the evaluator recursively evaluates Plus[3,4] and Plus[5,6] but finds no a rule for f
so it’s work is done.
58. Apply lets us change a Head
In[1] :=
Apply[Plus, f[3+4, 5+6]]
Out[1]:=
18
Apply lets us change the Head of an expression. We change the head of f[7,11] to Plus and
the evaluator keeps on going. You could name Apply SetHead.
59. Rules: Set
In[1] :=
x = Random[]
Out[1]:=
0.114681
We set a Symbol’s replacement rule with =. The right hand side of Set is evaluated right now.
60. x has a value
In[1] :=
{x, x, x}
Out[1]:=
{0.114681, 0.114681, 0.114681}
Each time we rewrite the symbol x the replacement is the same.
61. Rules: SetDelayed
In[1] :=
y := Random[]
We can set a Symbols replacement rule with := which is SetDelayed. The right hand side of
SetDelayed is not evaluated right now.
62. Rules: SetDelayed
In[1] :=
{y, y, y}
Out[1]:=
{0.304997, 0.897893, 0.00343832}
The Random[] on the right side will be evaluated every time the evaluator rewrites y.
63. Rules: OwnValues
In[1] :=
Out[1]:=
{OwnValues[x], OwnValues[y]}
{{HoldPattern[x] :> 0.114681},
{HoldPattern[y] :> Random[]}}
Rather that assigning to memory locations Symbols are bound to values by rules.
Mathematica calls these OwnValues. We will later talk about DownValues, and UpValues.
The :> is RuleDelayed.
HoldPattern is another mention mechanism that is just for patterns.
64. Patterns
In[1] :=
_
Out[1]:=
_
It’s time to better understand patterns. A pattern is a Mathematica expression that represents
an entire class of expressions.
This is the simplest, Blank[]
66. Blank with Head
In[1] :=
Hold[_f] //FullForm
Out[1]:=
Hold[Blank[f]]
This form of Blank will only match if the expression has a Head that is f.
67. Matching
•
•
•
•
•
•
•
_
Blank
__ BlankSequence (one or more)
___ BlankNullSequence (0 or more)
|
Alternatives
:
Optional
..
Repeated
?
PatternTest
Patterns are just expressions and Mathematica has a lot of expressive power for building
Pattern expressions.
69. Replacement Rules
In[1] :=
5 x + 19.5 x^2 /. v_Real -> v^2
Out[1]:=
5 x + 380.25 x^2
/. is ReplaceAll. I can give ReplaceAll a list of replacement rules. ReplaceAll is a built in that
is like a simplified form the the Mathematica evaluator.
70. Rules
In[1] :=
Hold[v_Integer -> v^2] // FullForm
Out[1]:=
Hold[Rule[Pattern[v,Blank[Integer]],Power[v,2]]]
Rules are where Mathematica gets its power. Mathematica uses rule based programming
paradigm. You write down a set of rules that specify a transformation to be applied to some
expressions. The system figures out the order in which these rules are to be applied.
71. Destructuring
In[1] :=
f[m] + g[n] /. x_[y_] -> y[x]
Out[1]:=
m[f] + n[g]
Extracting parts of expressions using pattern variables is called destructuring.
With this capability you can do just about anything. This is why I call Mathematica a building
material.
74. Factorial Matching Style
In[1] :=
fact[5] //. {fact[0] :> 1, fact[x_] :> x * fact[x - 1]}
Out[1]:=
120
This is an interesting inversion of thinking. The syntax //. is for the function
ReplaceRepeated and it keep evaluating until the expression no longer changes. It doesn’t
grow any stack when executed but the expression probably gets longer until the end when
the evaluator gets it’s hand on the expression and reduces all the multiplication.
75. Look closer with FixedPointList
In[1] :=
FixedPointList[# /. {fact[0] :> 1, fact[x_] :> x * fact[x - 1]} &,
fact[5]]
Out[1]:=
{fact[5], 5 fact[4], 20 fact[3], 60 fact[2], 120 fact[1],
120 fact[0], 120, 120}
Let’s look at it with FixedPointList and ReplaceAll. It looks like it is multiplying the numbers
out before transforming fact[n]. Or is it that the Mathematica evaluator doing it’s things
before we see it?
76. In[1] :=
f[x_, y_] := body;
In[2] :=
f[a, b]
ReleaseHold[Hold[body] /. {x :> a, y:>b}]
It is best to think of everything mathematica does as term rewriting. This expression could be
step of the evaluator. This is just an approximation because Mathematica has to take scoping
constructs into account but this gives you the idea.
77. Enough with factorial already!
In[1] :=
Clear[factorial];
factorial[0] := 1;
factorial[x_Integer] := Apply[Times, Range[x]]]
factorial[x_] := Gamma[x-1];
All right, maybe we can really be done with factorial. You want to learn to leverage
Mathematica’s functional building blocks and trans gigantic library. You probably don’t want
to write Gamma yourself.
78. Symbols have Attributes
•
•
•
•
•
•
•
HoldFirst
HoldRest
HoldAll
Listable
Flat
Orderless
...
There is a way to give the evaluator special instructions by putting some interesting attributes
on a Symbol. We will look at HoldFirst, HoldRest, HoldAll, and Listable. We will try to get to
Flat and Orderless but that will probably have to wait for another day. Flat, and Orderless is
how Mathematica deals with Associativity and Commutativity. Orderless keeps the number of
rules down by Sorting. If it’s Commutative you can sort. There are other attributes that you can
read about in the Mathematica documentation.
79. Attribute: HoldFirst
In[1] :=
SetAttributes[f,HoldFirst];
In[2] :=
f[3+4, 5+6]
Out[1]:=
f[3+4, 11]
There is a way to give the evaluator special instructions by putting some interesting attributes
on a Symbol. We will look at HoldFirst, HoldRest, and HoldAll
81. Attribute: HoldAll
In[1] :=
Clear[f];
SetAttributes[f,HoldAll];
In[2] :=
f[3+4, 5+6]
Out[1]:=
f[3+4, 5+6]
We can arrange for the symbol f when used as a head to withhold evaluation for either the first
expression, all but the first, or just hold all of exprssions.
Let's go on a rampage.
82. Control
In[1] :=
In[2] :=
Out[1]:=
In[2] :=
Out[1]:=
SetAttributes[if, HoldRest];
if[True, thenPart_, elsePart_] := thenPart;
if[False, thenPart_, elsePart_] := elsePart;
x = 10;
if[x < 100, 3+4, 5+6]
7
if[x > 100, 3+4, 5+6]
11
Time to make our own control construct.
When the evaluator sees an expression who’s Head is the symbol if it will evaluate the first
argument and hold evaluation on the rest of the arguments.
We will make a pair of rules for if. One for the True part and one for the False part.
Having the thenPart or the elsePart for the result of the rule just lets the evaluator evaluate
that which was held.
This kind of rule is a DownValue. What looks like a function is usually a DownValue.
The fractorial function from before was a DownValue
83. Is this a Bug?
In[1] :=
if[100, 3+4, 5+6]
Out[1]:=
if[100, 3+4, 5+6]
Take that! Is our if construct flawed? The last case is not an error in our if design, it is a
perfectly good expression. You may learn to like this. The possibly un-expected result is in
your face, preserved so you can see the truth of what is. We could make a new rule for if that
would yell at us but that isn’t really the Mathematica way.
84. Will It Map?
In[1] :=
Map[if[# < 10, # * #, # + #] &, {5, 6, 25, 50, "die"}]
Out[1]:=
{25, 36, 50, 100, if["die" < 10, "die" "die", "die" + "die"]}
Now we can just use our if in functions and higher order functions.
85. FEXPRS
Check out the material by John Shutt on Vau-Calculus at:
http://fexpr.blogspot.com.
Back in the old days in Lisp we had FEXPRS but macros won out because they are very
compiler friendly. There is a bit of a revival of FExprs going on. Check out the material by
John Shutt on vau-calculus at http://fexpr.blogspot.com.
86. There is nothing special about Hold
In[1] :=
SetAttributes[hold,HoldAll];
releasehold[hold[x___]] := x
In[2] :=
releasehold[hold[3 + 4, 5 + 6]]
Out[1]:=
Sequence[7, 11]
Let’s make our own version of Hold. There is a lot to see here. The pattern variables do not
have to be at the top level. We get a destructuring bind. Sequence is cool. It gets spliced into
expressions and can be controlled with the attribute SequenceHold.
87. Sequence Splices
In[1] :=
{releasehold[hold[3 + 4, 5 + 6]]}
Out[1]:=
{7, 11}
Let’s just put that expression inside a List and watch Sequence splice. Sequence is a great
building block. One of the attributes is SequenceHold which inhibits the splicing.
90. Function: A Very Interesting Head
In[1] :=
Function[3+4]
Out[1]:=
3+4&
First let's look at the most interesting scoping mechanism of all space-time, Function.
Function is a Mathematic expression. Function the expression is the perfect Head. Remember,
a Head does not have to be limited to a Symbol. Function is the basic deferred evaluation
mechanism for code. It makes code a be literal.
91. In[1] :=
Function[3 + 4] // FullForm
Out[1]:=
Function[Plus[3,4]]
Here Function acts just like Hold.
92. In[1] :=
Function[3+4][]
Out[1]:=
7
And here we evaluate it by letting it be the Head of an Expression. This is a SubValue, you can
make your own SubValues. Sadly we will not go there today.
94. Function: A Very Interesting Result
In[1] :=
Function[{x}, Function[{y}, x*y]] [3]
Out[1]:=
Function[{y$}, 3 y$]
Here is a Function that returns a Function. Mathematica makes new variable names because
the x bound in the outer function and is free in the inner function. Ok, let's do that factorial
thing again but with function.
95. Y: A Very Interesting Function
Avert your eyes!
In[1] :=
y := Function[f,
Function[x,
f[Function[y, x[x][y]]]][Function[x, f[Function[y, x[x][y]]]]]]
This is one of the right of passage functions for functional programming. My vote for second
best all time function after eval. The Y Combinator also known as the fixed point combinator.
Y lets you call a function recursively without needing to have a name for that function.
Don’t try to understand it right now.
96. Oh No, Factorial Again!
Please don’t look at that result!
In[1] :=
Out[1]:=
factorial = y[Function[f, Function[n, If[ n == 0, 1, n * f[n - 1]]]]]
Function[n$, If[n$ == 0, 1, n$ Function[y$, Function[x$,
Function[f, Function[n, If[n == 0, 1, n f[n - 1]]]]
[ Function[y$, x$[x$][y$]]]][ Function[x$,
Function[f, Function[n, If[n == 0, 1, n f[n - 1]]]]
[Function[y$, x$[x$][y$]]]]][y$]][n$ - 1]]]
So if we pass a function that does what factorial does to Y we get a recursive factorial
function.
98. No Names Needed
In[1] :=
y[Function[f, Function[n, If[ n == 0, 1, n * f[n - 1]]]]] [5]
Out[1]:=
120
When it is doing it job y make a function just in time. This is a fixed point for functions.
99. Read about Y
Read about this wonderful function called Y
at Dick Gabriel's website:
http://www.dreamsongs.com/Files/WhyOfY.pdf
If you hate this kind of thing no worries. If you think you might be interested I will refer you
to a great article on Y.
100. With
With[{x = x0, y = y0, z = z0}, expr]
A closely related construct to Function in Mathematica is With. With comes off as more
syntactic but let's you replace names in an expression with values. The names are local
constants.
The x, y and z are replaced inside the expression before the expression is executed. You can
use it like Lisps Let. It is an essential for meta-programming. You can inject code into held
expressions that are templates then you use Apply on the way out to change the Head to
Function.
101. Meta Programming
In[1] :=
strides[dims_] := Map[Apply[Times, #] &,
NestList[Rest, Rest[dims ~Join~ {1}], Length[dims] - 1]];
indexer[shape_] :=
With[{syms = Map[Unique[a] &, shape], shp = strides[shape]},
With[{pat = 1 + (Plus @@ Apply[Times, Partition[Riffle[syms, shp], 2], 1])},
Function @@ Hold[syms, pat]]];
In[2] :=
indexer[{3, 3, 9}]
Out[1]:=
Function[{a$69734, a$69735, a$69736}, 1 + 27 a$69734 + 9 a$69735 + a$69736]
Sorry for the different font size. With is an essential for meta-programming. You can inject
code into held expressions that are templates then you use Apply on the way out to change
the Head to Function.
102. Block
In[1] :=
{x, y, z} = {3, 4, 5};
In[2] :=
Block[{x = 10, y = 20, z = 30}, {x, y, z}]
Out[1]:=
{10, 20, 30}
In[3] :=
{x, y, z}
Out[2]:=
{3,4,5}
Block has some of the taste of old Lisp's dynamic binding. This is useful when you
sometimes want to set a global to a different value during an evaluation and then have it return
to what it was. Think of this as having the ability to have local values.
103. Module
Module[{x,y,...}, expr]
Module[{x = x0, y = y0, …}, expr]
Finally there is Module. Module let's you setup a local environment where the names are local
to the module.
Module creates new symbols with gensym to represent the variable names each time module
is called.
104. In[1] :=
Out[1]:=
Module[{l = {}, count = 10, i},
For[i = 0, i < count, i++,
l = Append[l, i]];
l]
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
You can use Module to keep your locals in their own scope.
This is terrible Mathematica Code but sometimes you just need to be imperative.
105. Make Y Combinator Pretty
In[1] :=
y := Function[f,
Module[{g = Function[h, Function[x, f[h[h]][x]]]}, g[g]]];
Let me wash the stink of imperative code off by using Module to make Y combinator pretty.
106. Make Objects in a Functional Way
In[1] :=
makeAccount[name_, start_] :=
Module[{accname = name, balance = start},
account[
Function[accname],
Function[x,balance = balance + x],
Function[x,balance = balance - x],
Function[balance]]];
Let’s have a little bit of fun and make Objects out of closures. This is a classic style from SICP
Structure and Interpretation of Computer Programs. The head account acts like a struct that
holds our functions.
107. Cool, but what an ugly expression
In[1] :=
Out[1]:=
acc1 = makeAccount["david", 1000]
account[
accname$89163 &,
Function[x$, balance$89163 = balance$89163 + x$],
Function[x$, balance$89163 = balance$89163 - x$],
balance$89163 &]
Now that result is an expression only a mother could love. Not the gensymed symbols.
108. FormatValues
In[1] :=
Format[account[n_Function, _, _, _]]
:= StringJoin["account[", n[], "]"];
In[2] :=
acc1
Out[1]:=
account[david]
Here is another kind of capability for Symbols. Format let’s us talk to the mechanism that
displays expressions that have the Symbol account for a Head. Now the account object does
not look so ugly and we can’t see inside it unless we use FullForm
109. Standard DownValue
In[1] :=
name[account[n_Function, _, _, _]]
:= n[];
deposit[account[_, d_Function, _, _], amt_] := d[amt];
withdraw[account[_, _, w_Function, _], amt_] := w[amt];
balance[account[_, _, _, b_Function]]
:= b[];
In[2] :=
balance[acc1]
Out[1]:=
1000
You see here that I am going to match different functions in the account object. The evaluator
will do a destructuring bind for us. The _ pattern matches anything. Putting the Head Function
on bf_Function is saying that the evaluator should only match if we are given a Function. I
hear you signature purists screaming. What if I made a bad function and stuffed it inside an
account. That would be so sad. :-( Note, we could generate these functions with a little bit of
meta-programming.
110. UpValues
In[1] :=
account /: Plus[a : account[___], b_]
:= b + balance[a];
account /: Plus[a : account[___] , b : account[___]]
:= balance[a] + balance[b];
In[2] :=
acc1 + 100
Out[1]:=
1100
In[3] :=
acc1 + acc1
Out[2]:=
2000
We could open up Plus and add a new definition but that would slow down all arithmetic.
Instead we will create an UpValue. This kind of rule goes with the Symbol account. The
evaluator looks at the Heads of arguments and finds a match and evaluates our rule.
Think of DownValues as looking from the symbol that is the Head downward into the
expression. Think of UpValues as being down in the expression and looking upward towards
the Head.
112. Memoizing Fibonachi
In[1] :=
In[2] :=
Out[1]:=
Clear[fib];
fib[0] = fib[1] = 1;
fib[n_] := fib[n] = fib[n-1] + fib[n-2];
fib[100]
573147844013817084101
We can use DownValues as a little database. This is good for memoizing;
113. Make Transformation Rules
ClearAll[pushR, popR, dupR, swapR, rotR, topR, nextR];
(* stack-to-stack transforms *)
pushR = {{stack___}, datum_} :> {datum, stack};
popR = {{top_, rest___} :> {rest}};
dupR = {{top_, rest___} :> {top, top, rest}};
rotR = {{top_, rest___} :> {rest, top}};
swapR = {{top_, next_, rest___} :> {next, top, rest}};
(* stack-to-value transforms *)
topR = {{top_, rest___} :> top};
nextR = {{top_, next_, rest___} :> next};
The rule based programming with rewrite rules lets us make languages. Brian Beckman
encouraged me to make the effort to invert my thinking about programming. This is one of the
things he taunted me with. These are stack-to-stack transforms for a Fourth like language.
They are all defined as rules. The stack is maintained as a list. I just draw a picture of the
stack with literal expressions involving patterns and let the matcher do the work.
114. Microcode for a Fourth Machine
ClearAll[exec,execAll];
microcode = Dispatch@{
(*BINARIES*)
{stack_,plus}:>With[{r=(stack/.nextR)+(stack/.topR)},
{stack/.popR/.popR,r}/.pushR],
{stack_,times}:>With[{r=(stack/.nextR)*(stack/.topR)},
{stack/.popR/.popR,r}/.pushR],
{stack_,minus}:>With[{r=(stack/.nextR)-(stack/.topR)},
{stack/.popR/.popR,r}/.pushR],
{stack_,div}:>With[{r=(stack/.nextR)/(stack/.topR)},
{stack/.popR/.popR,r}/.pushR],
{stack_,uminus}:>({stack/.popR,-(stack/.topR)} /. pushR),
(*NULLARIES*)
{stack_,pop}:>(stack/.popR),
{stack_,dup}:>(stack/.dupR),
{stack_,rot}:>(stack/.rotR),
{stack_,swap}:>(stack/.swapR),
(*UNARY-- DEFAULT*)
{stack_,x_}:>({stack,x}/.pushR)};
Here are more rules. Dispatch builds compiles the rules into something that efficiently
executes the transformations.
115. A little functional code
exec = machineState : {stack_, instr_} :> (machineState /. microcode);
execAll = {stack_, {instr_, instrs___}} :> ({{stack, instr} /. exec, {instrs}});
execute[stack_, instrs_] := First[First[FixedPoint[x ⊂ x /. execAll, {stack, instrs}]]];
execAllTrace[stack_, instrs_] :=
Module[{history = First /@ FixedPointList[x ⊂ x /. execAll, {stack, instrs}] // Most},
Grid[Partition[Join[{start}, Riffle[history, instrs]], 2], Frame -> All]];
We use a functional style to sequence the execution of the rules. FixedPoint is the iteration
pattern that works best here. We also build a visualization interface with FixedPointList so we
can observe the execution in a human understandable way.
116. Execute and Observe
In[1] :=
execAllTrace[{}, {a, b, 3, 4, plus, rot, div, plus}]
Out[1]:=
I always had a hard time with Fourth because I just couldn’t keep what the evaluator was
doing in my head. Here I can see what is happening. I like to externalized the processs of
execution with some kind of visualization. This is like distributed cognition. Of course I can
just do it symbolically too. I have built array programming languages that animate the
intermediate results of the data flow as the computation moves from expression to
expression.
117. Compiling
In[1] :=
cP1 = Compile[{{x}},
Module[{sum = 1.0, inc = 1.0},
Do[inc = inc*x/i; sum = sum + inc, {i, 10000}]; sum],
RuntimeAttributes -> {Listable}, Parallelization -> True,
CompilationTarget -> "C"];
In[2] :=
arg = Range[ -50., 50, 0.02];
cP1[arg]; // AbsoluteTiming
Out[1]:=
{0.4531395, Null}
This example comes right out of the Mathematica Documentation Notebook.
Compiling is very cool and let’s you build things that scale very well. When you combine the
ability of meta-programming, partial-evaluation, and all of mathematics with the ability to
compile at a function level of granularity you can do some amazing things.
118. Watch the video with slide synchronization on
InfoQ.com!
http://www.infoq.com/presentations/mathematica
-programming-language