Introduction
Introduction
This document is a copy of the presentation materials I used at a workshop I gave at the MIT Future Tech Lab in February 2025. The talk covered a brief introduction to functional programming and exemplary functional programming constructs in Wolfram Language (WL). Since some audience members were new to WL, the materials also include a brief introduction to basic programming concepts in the language.
Functional programming is a paradigm that treats computation as the evaluation of mathematical functions and avoids changing state or mutable data. It’s a core part of Wolfram Language, and idiomatic WL code will often have a functional flavour. Whether you’re a seasoned programmer or just starting out, learning to write in a functional style can give you a fresh perspective on problem-solving and often make your code more performant and parallelizable, making it a valuable addition to your programming toolkit.
Teasers: Example Functional Style Programs
Teasers: Example Functional Style Programs
Introduction to WL
Introduction to WL
Introduction to Functional Programming
Introduction to Functional Programming
Wolfram Language is a multi-paradigm programming language. It supports procedural programming and OOP, but is designed to encourage programmers to code in a functional style.
Functional programming in WL typically results in more performant code.
What is Functional Programming?
What is Functional Programming?
1
.Ideal Functional programming:
◼
Writing programs using only mathematical functions: (a function is a map between sets). A function called twice with the same arguments should return the same result.
◼
No concept of state. No variable assignments ever, and no reading values from the environment.
◼
BIG CAVEAT: It turns out that in a purely functional language (without the notion of state) you can’t really do anything.
2
.Functional programming as a programming style:
◼
No real-world programming language is purely functional: It would be better to think of functional languages as languages that strive to be as functional as possible.
◼
Functional programming languages encourage programmers to code in a functional style:
◼
Writing programs with functions, higher order functions (functions that take other functions as arguments), and compositions of functions.
◼
Being as clear as possible about the side effects, failure cases and misbehaviours a function may have.
◼
Using functional constructs and design patterns when possible.
Guiding Principles of Functional Programming
Guiding Principles of Functional Programming
◼
Make functions the building blocks of your programs.
◼
If a process is being reused throughout a program, it should be its own function.
◼
If a process is large enough that it would be cumbersome to rewrite, and there is a chance you might like to reuse it later, it should be a function.
◼
In WL, you are encouraged to implement function polymorphism using overloading (let me know if you’d like to see an example).
◼
Minimise the number of variables you define, and limit side-effects by avoiding altering variables beyond the scope of any given function.
◼
Side effects are behind all sorts of common and some more obscure and creative bugs in procedural and OOP programs.
◼
Avoid procedural constructs like or in favour of functional constructs like , , or .
◼
If possible, a function called twice with the same arguments should return the same result (in practice, we break this rule all the time).
Reading Functional Code
Reading Functional Code
Read code from the inside out:
◼
Since programs are functions definitions + function compositions, whenever you use a higher order function, the arguments of the function have to be evaluated before the function can be evaluated.
◼
In practice, this means that when you have many function compositions (e.g. f[g[h[x]]]) , the code can best be made sense of by reading from the deepest point outwards.
Bonus note: You can write function calls using brackets, prefix, or postfix notation, depending on your preferred style:
In[]:=
f[g[h[x]]]===(f@g@h@x)===(x//h//g//f)
Out[]=
True
Perks of Functional Programming
Perks of Functional Programming
◼
Functional programming is often more declarative than procedural and OOP programming styles.
◼
Functional style programs make it easier to debug, as issues are often easier to trace to misbehaving functions.
◼
In functional programming (when your function is a true function in the mathematical sense), you can always safely run two functions in parallel because there are no side effects. There are no ways for the functions to interfere with each other.
◼
Lower reliance on design patterns in programming (not quite true: for example, , , and monads are design patterns).
◼
In practice, you should program using a mix of paradigms depending on the nature of the task at hand. Functional and OO and procedural code really all have their own advantages, and can be combined.
Further Reading/Learning Resources
Further Reading/Learning Resources
◼
Functional Constructs in Wolfram Language
Functional Constructs in Wolfram Language
The following are some really common functional operations.
Function
Function
In[]:=
Function[x,x+1];
In[]:=
Function[{x,y},x+y];
In[]:=
#1+1&;
In[]:=
#1+#2&;
Array and Table
Array and Table
In[]:=
Array[a,{2,2}]//MatrixForm
Out[]//MatrixForm=
a[1,1] | a[1,2] |
a[2,1] | a[2,2] |
Array[Subscript[a,##]&,{3,3}]//MatrixForm
Out[]//MatrixForm=
a 1,1 | a 1,2 | a 1,3 |
a 2,1 | a 2,2 | a 2,3 |
a 3,1 | a 3,2 | a 3,3 |
In[]:=
Array[RandomColor[]&,{3,3,3}]
Out[]=
{{{,,},{,,},{,,}},{{,,},{,,},{,,}},{{,,},{,,},{,,}}}
In[]:=
Image3D
Out[]=
Thread
Thread
The function is used to apply a function across lists in its arguments. It effectively “threads” the function over the elements of the lists, aligning them by their positions:
In[]:=
Thread[something[{1,2,3}]]
Out[]=
{something[1],something[2],something[3]}
In[]:=
Thread[something[{1,2,3},{a,b,c}]]
Out[]=
{something[1,a],something[2,b],something[3,c]}
Threading over List is equivalent to :
In[]:=
Thread[List[{1,2,3},{a,b,c}]]
Out[]=
{{1,a},{2,b},{3,c}}
Maps (Map, MapApply, MapThread)
Maps (Map, MapApply, MapThread)
Map
Map
Use to apply a function to each element at a specific level in an expression. By default, it applies the function to each element at the first level:
Apply a function to an expression at level 1:
In[]:=
Map[f,{a,b,c}]
Out[]=
{f[a],f[b],f[c]}
Apply a function to an expression at level 2:
In[]:=
Map[f,{{a,b,c},{d,e,f}},{2}]
Out[]=
{{f[a],f[b],f[c]},{f[d],f[e],f[f]}}
Apply a function to an expression at levels 1 through 2:
In[]:=
Map[f,{{a,b,c},{d,e,f}},2]//MatrixForm
Out[]//MatrixForm=
f[{f[a],f[b],f[c]}] |
f[{f[d],f[e],f[f]}] |
Comap
Comap
While distributes a function over elements, distributes elements over functions:
Apply a list of functions to an input:
In[]:=
Comap[{f,g,h},x]
Out[]=
{f[x],g[x],h[x]}
Apply
Apply
In[]:=
Apply[f,{a,b,c}]
Out[]=
f[a,b,c]
MapApply
MapApply
MapThread
MapThread
Map a function over corresponding arguments from two lists:
Nests (Nest, NestList, NestTree, NestGraph)
Nests (Nest, NestList, NestTree, NestGraph)
Nest
Nest
NestList
NestList
NestTree
NestTree
NestGraph
NestGraph
Generate a k-hop network of related WL functions rooted at Nest:
Folds (convenient for avoiding state)
Folds (convenient for avoiding state)
Pattern Matching
Pattern Matching
Match any single expression:
Match any single expression with the head Integer:
Match any even number:
Match any number that is even and evenly divisible by 3:
Define a list elements:
List cases of Graph elements in the list:
These are some very simple examples, but the pattern matching rabbit hole goes deep.
Query, Dataset, and Tabular
Query, Dataset, and Tabular
Use Query to process data:
Represent hierarchical or tabular data in WL:
Use Query implicitly to apply functions at different levels of the datasets.
As of Wolfram Language 14.2, we also have a new construct called Tabular which is designed to make traditional data science pipeline operations (wrangling, reshaping, or summarising tabular data) easy:
Brief note on monads
Brief note on monads
A monadic pattern is a design pattern in functional programming that allows for operation chaining while managing context and control flow. It takes advantage of the properties of an object found in category theory: the monad.
(In practice monads in functional programming are a little different from the ones found in category theory.)
“Simply put, monads provide a generalized interface to sequential computation. Hence monads are a way to impose or enforce a certain regular behavior in building computations.” (Anton Antonov - Mathematica StackExchange)
In Functional Programming, What’s a Monad, Really?
In Functional Programming, What’s a Monad, Really?
First, let’s define the two functions needed to make a monad:
Example:
Example:
Okay, now let’s define some functions f and g that satisfy the bind condition:
For something to be a monad, in addition to implementing unit and bind, it has to follow some rules:
Monadic Code in WL
Monadic Code in WL
Demonstrate that the monad laws are satisfied:
Example of some monadic functional code:
Further Reading/Learning Resources
Further Reading/Learning Resources
◼
A monad is a design pattern in which
My favourite ones:
Some more:
◼
A quote from this: “Simply put, monads provide a generalized interface to sequential computation. Hence monads are a way to impose or enforce a certain regular behavior in building computations.”
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
A short introduction to functional programming and Wolfram Language functional constructs
by Phileas Dazeley-Gaist
Wolfram Community, STAFF PICKS, April 2, 2025
https://community.wolfram.com/groups/-/m/t/3437953
by Phileas Dazeley-Gaist
Wolfram Community, STAFF PICKS, April 2, 2025
https://community.wolfram.com/groups/-/m/t/3437953