introduction to functional programming using ocaml
DESCRIPTION
Key Functional Programming concepts illustrated using OcamlTRANSCRIPT
Introduction to Functional Programming withOcaml
Pramode C.E
http://pramode.net
January 30, 2014
Workshop Plan
Here is what we will do:
Learn some Ocaml syntax and write simple Ocaml programs
Learn important concepts like: closures, higher order functions,purity, lazy vs strict evaluation, currying, tail calls/TCO,immutability, persistent data structures, type inference etc!
Understand the essence of the "Functional Programming"paradigm through Ocaml
Not beginner-level stu� - but I will try to keep things as simple aspossible!
Pramode C.E Introduction to Functional Programming with Ocaml
Ocaml - some background info
Written in 1996 by Xavier Leroy and other researchers atINRIA, France
A member of the ML familyhttp://en.wikipedia.org/wiki/ML_(programming_language)
Supports Functional, Imperative and Object orientedprogramming
A powerful static type system with type inference
Major in�uence behind Microsoft F#
Recent developments: the Core standard library (by JaneStreet) and realworldocaml.org
Pramode C.E Introduction to Functional Programming with Ocaml
Pramode C.E Introduction to Functional Programming with Ocaml
Where is it being used?
List of companies: http://ocaml.org/learn/companies.html
Facebook - p�f, a tool for analysing PHP source
Citrix - Uses Ocaml in XenServer, a virtualization system
Jane Street - develops trading systems in Ocaml
Bloomberg - uses Ocaml for developing �nancial derivativesrisk management applications
Pramode C.E Introduction to Functional Programming with Ocaml
The Ocaml REPL
Invoke the REPL with the "utop" command at the shell prompt:
utop # print_string "hello\n";;
hello
- : unit = ()
utop # 2 * 3;;
- : int = 6
utop # let x = 10;;
val x : int = 10
utop # x * 2;;
- : int = 20
utop # let y = 5 in y * 8;;
- : int = 40
utop #
Question: what is the di�erence between "let" and "let ... in"?
Pramode C.E Introduction to Functional Programming with Ocaml
Function De�nition
let add a b = a + b
let m = add 10 20
We de�ne add to be a function which accepts two parameters oftype int and returns a value of type int. Similarly, m is de�ned as avariable of type int.
But wait ... we haven't actually de�ned all these types!
Pramode C.E Introduction to Functional Programming with Ocaml
Type Inference
We have NOT speci�ed the return type of the function or the typeof the variable m. Ocaml infers that (the technical term is Hindley-Milner type inference)
This is the type which utop shows us:val add : int -> int -> intRead this as: function takes two int's as arguments and returns anint.
Pramode C.E Introduction to Functional Programming with Ocaml
Static vs Dynamic typing
#Python - dynamic typing
def foo(x): return x/2
/* C - static typing with NO type inference */
int foo(int x) { return x / 2; }
(* ML - static typing with type inference *)
let foo x = x / 2
Pramode C.E Introduction to Functional Programming with Ocaml
Expression Oriented Programming
let i = 0
let p = if (i > 0) then -1 else -2
let q = if (true) then "hello" else "world"
Unlike languages like C/Java, almost everything in Ocaml is anexpression, ie, something which computes a value! Rather thanprogramming with statements, we program with expressions.
Pramode C.E Introduction to Functional Programming with Ocaml
Recursion
(* compute sum of first n numbers *)
let rec sum n =
if (n = 0) then 0 else n + sum (n - 1)
let r = sum 10
Try calling the function "sum" with a large number (say 1000000)as parameter! You get a stack over�ow!
Pramode C.E Introduction to Functional Programming with Ocaml
Tail Calls and TCO
(* compute sum of first n numbers *)
let rec sum n acc =
if (n = 0) then acc else sum (n - 1) (acc + n)
let r = sum 10 0
This is a "tail-recursive" version of the previous function - theOcaml compiler converts the tail call to a loop, thereby avoidingstack over�ow!
Pramode C.E Introduction to Functional Programming with Ocaml
Tail Calls and TCO
(sum 4)
(4 + sum 3)
(4 + (3 + sum 2))
(4 + (3 + (2 + sum 1)))
(4 + (3 + (2 + (1 + sum 0))))
(4 + (3 + (2 + (1 + 0))))
(4 + (3 + (2 + 1)))
(4 + (3 + 3))
(4 + 6)
(10)
------------------------------
(sum 4 0)
(sum 3 4)
(sum 2 7)
(sum 1 9)
(sum 0 10)
(10)
-------------------------------Pramode C.E Introduction to Functional Programming with Ocaml
Parametric polymorphism
let foo x = x
Our function "foo" is the identity function; it takes in a value andreturns the same! What is the inferred type of this function?
More examples:
let foo x y = x
let foo2 x y = if true then x else y
let foo3 x y = if x then y else y
let foo4 x y = if x then y else x
Pramode C.E Introduction to Functional Programming with Ocaml
Higher order functions
let double x = 2*x
let triple x = 3*x
let apply f x = f x
let p = apply double 10
let q = apply triple 10
What is type of "apply"?
Pramode C.E Introduction to Functional Programming with Ocaml
Summation once again!
let sqr x = x * x
let cube x = x * x * x
let rec sumSimple a b =
if a = b then a else a + sumSimple (a + 1) b
let rec sumSquares a b =
if a = b then (sqr a) else (sqr a) + sumSquares (a + 1) b
let rec sumCubes a b =
if a = b then (cube a) else (cube a) + sumCubes (a + 1) b
Pramode C.E Introduction to Functional Programming with Ocaml
Summation - a more elegant method
let identity x = x
let sqr x = x * x
let cube x = x * x * x
let rec sum f a b =
if a = b then (f a) else (f a) + sum f (a + 1) b
let p = sum identity 0 4
let q = sum sqr 0 4
let r = sum cube 0 4
Pramode C.E Introduction to Functional Programming with Ocaml
Anonymous functions
let apply f x = f x
let p = apply (fun x -> 2*x) 10
We can create "anonymous" functions on-the-�y! fun x -> 2*x is afunction which takes an "x" and returns 2*x.
Pramode C.E Introduction to Functional Programming with Ocaml
Methods on collections: Map/Filter/Reduce
open Core.Std
let a = [1;2;3;4]
let p = List.map a (fun x -> x * x)
let q = List.filter a (fun x -> (x mod 2) = 0)
let r = List.reduce a (fun x y -> x + y)
Map applies a function on all elements of a sequence. Filter selectsa set of values from a sequence based on the boolean valuereturned by a function passed as its parameter - both functionsreturn a new sequence. Reduce combines the elements of asequence into a single element.
Pramode C.E Introduction to Functional Programming with Ocaml
More methods on collections
open Core.Std
let even x = (x mod 2) = 0
let a = [1;2;3;4;5;6;7]
let b = [2;4;6;5;10;11;13;12]
let c = List.for_all a even
let d = List.exists a even
let e = List.take_while a even
let f = List.partition_tf a even
Pramode C.E Introduction to Functional Programming with Ocaml
Nested functions / functions returning functions
(* foo returns sqr *)
let foo () =
let sqr x = x * x in sqr
let f = foo ()
let g = f 10
Pramode C.E Introduction to Functional Programming with Ocaml
Lexical Closure
let foo1 x = let foo2 y = x + y in foo2
let f = foo1 10
let r = f 20
Pramode C.E Introduction to Functional Programming with Ocaml
Lexical Closure
The function "foo1" returns a "closure".
A "closure" is a function which carries with it references to theenvironment in which it was de�ned.
When we call f(20), the "foo2" function gets executed withthe environment it had when it was de�ned - in thisenvironment, the value of "x" is 10.
Pramode C.E Introduction to Functional Programming with Ocaml
Simple closure examples
let sqr x = x * x
let cube x = x * x * x
let compose f g = fun x -> f (g x)
let f = compose sqr cube
let m = f 2
Pramode C.E Introduction to Functional Programming with Ocaml
Simple closure examples
open Core.Std
let remove_low_scores xs threshold =
List.filter xs (fun score -> score >= threshold)
let m = remove_low_scores [20; 35; 80; 92; 40; 98] 50
The anonymous function fun score -> score >= threshold isthe closure here.
How do you know that it is a closure? Its body uses a variable"threshold" which is not in its local environment (the localenvironment, in this case, is the parameter list consisting of asingle parameter "score")
Pramode C.E Introduction to Functional Programming with Ocaml
Currying and Partial Application
Here is the de�nition from Wikipedia:
In mathematics and computer science, currying is the technique oftransforming a function that takes multiple arguments (or a tupleof arguments) in such a way that it can be called as a chain offunctions, each with a single argument. It was originated by MosesSchon�nkel and later re-discovered by Haskell Curry.
Pramode C.E Introduction to Functional Programming with Ocaml
Currying and Partial Application
let add x y = x + y
let f = add 10
let g = f 20
The type of "add" is int -> int -> int. The correct way to read thisis: add takes an int as argument and returns a function which mapsan int to an int.
Pramode C.E Introduction to Functional Programming with Ocaml
Currying and Partial Application
let add x y z = x + y + z
let f = add 10
let g = f 20
let h = g 30
Pramode C.E Introduction to Functional Programming with Ocaml
Algebraic Data Types - Product types
let a = (1, 2) (* type: int*int *)
let b = ("hello", 10, 2) (* type: string*int*int *)
An Algebraic Data Type is a composite type - a type formed bycombining other types. Two classes of algebraic data types are theproduct and sum types.
Pramode C.E Introduction to Functional Programming with Ocaml
Algebraic Data Types - Sum types
type shape = Circle of int
| Square of int
| Rectangle of (int*int)
let a = Circle 10 (* circle of radius 10 *)
let b = Square 20 (* square with sides 20 *)
let c = Rectangle (5,10) (* rectangle with sides 5 and 10 *)
The type "shape" describes a shape which can be one of Circle,Square or Rectangle.
Pramode C.E Introduction to Functional Programming with Ocaml
Pattern Matching
let a = (1, (2, "hello"))
let (x, (y, z)) = a
Pattern matching helps you pull apart complex datastructures andanalyse their components in an elegant way (not to be confusedwith regular expression based pattern matching which is acompletely di�erent thing).
Pramode C.E Introduction to Functional Programming with Ocaml
Pattern Matching
type shape = Circle of float
| Square of float
| Rectangle of (float*float)
let area s = match s with
| Circle r -> 3.14 *. r *. r
| Square x -> x *. x
| Rectangle (x, y) -> x *. y
let a = area (Circle 10.0)
let b = area (Square 20.0)
let c = area (Rectangle (5.0,10.0))
Pramode C.E Introduction to Functional Programming with Ocaml
Pattern Matching
type shape = Circle of float
| Square of float
| Rectangle of (float*float)
let area s = match s with
| Circle r -> 3.14 *. r *. r
| Square x -> x *. x
let a = area (Circle 10.0)
let b = area (Square 20.0)
let c = area (Rectangle (5.0,10.0))
The compiler warns us when it detects that the match is not"exhaustive".
Pramode C.E Introduction to Functional Programming with Ocaml
Pattern Matching
let rec len xs =
match xs with
| [] -> 0
| hd :: tl -> 1 + len tl
let a = len [1;2;3;4]
A simple recursive routine for computing length of a list. If list isempty, length is 0, otherwise, it is 1 + length of remaining part ofthe list.
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability and the nature of variables
let a = 1
let foo x = x + a;
a = 2 (* simply compares a with 2 *)
let a = 0 (* earlier binding gets shadowed *)
let m = foo 10 (* result is 11 *)
let bindings are immutable; you can shadow a binding, but anearlier binding can't be mutated.
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability
Let's look at some Python list manipulation code:
a = [20, 30, 40, 50]
a.insert(0, 10)
print a # prints [10, 20, 30, 40, 50]
Python lists are mutable. The insert operation modi�es the originallist.
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability
Here is a similar program in Ocaml:
let a = [20;30;40;50]
let b = 10::a (* a remains unchanged *)
let c = [60;70;80]
let d = a @ c (* a remains unchanged *)
Good Ocaml style encourages use immutable data structures.
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability: Structure sharing
This is one way to implement 4::b - but it requires creating a fullcopy of the old list "b" (red-colored cells 1, 2, 3 are copies of cellscontaining the same values in "b") and adding 4 at the headposition. Ocaml does NOT do it this way because it is veryine�cient.
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability: Structure sharing
This is how Ocaml actually does 4::b. Note that the new list sharesall its elements (except 4) with the old list!
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability: Structure sharing
This is what happens when you append two lists A and B (using @in Ocaml). Note that the appending operation needs to copy thewhole of list A.
Pramode C.E Introduction to Functional Programming with Ocaml
Immutability: Structure sharing
The "structure sharing" idea can be used e�ciently with treedata structures.
For more info: http://en.wikipedia.org/wiki/Persistent_data_structure
Persistent vectors in Scala:http://www.codecommit.com/blog/scala/
implementing-persistent-vectors-in-scala
Pramode C.E Introduction to Functional Programming with Ocaml
Mutability and aliasing
a = [1,2,3,4]
b = a
b.append(5)
print a
Having aliases to mutable objects can create very hard to trackdown bugs in our code.
Pramode C.E Introduction to Functional Programming with Ocaml
Non-strict evaluation
let my_if cond then_part else_part =
if cond then then_part else else_part
let a = my_if (1 > 2) 10 20
We are trying to write a function which behaves similar to thebuilt-in "if" control structure in Ocaml ... does it really workproperly? Let's try another example!
Pramode C.E Introduction to Functional Programming with Ocaml
Non-strict evaluation
let foo1 () = print_string "foo1\n"; 10
let foo2 () = print_string "foo2\n"; 20
let my_if cond then_part else_part =
if cond then then_part else else_part
let a = my_if (1 > 2) (foo1()) (foo2())
Pramode C.E Introduction to Functional Programming with Ocaml
Non-strict evaluation
The behaviour of "if" is "non-strict": In the expression "if(cond) then e1 else e2", if "cond" is true e2 is NOTEVALUATED. Also, if "cond" is false, e1 is NOTEVALUATED.
By default, the behaviour of function calls in Ocaml is "strict":In the expression "fun e1 e2 ... en, ALL the expressions e1, e2... en are evaluated before the function is called.
Pramode C.E Introduction to Functional Programming with Ocaml
Non-strict evaluation
let foo1 () = print_string "foo1\n"; 10
let foo2 () = print_string "foo2\n"; 20
let my_if cond then_part else_part =
if cond then (then_part()) else (else_part())
let a = my_if (1 < 2) (fun () -> (foo1()))
(fun () -> (foo2()))
Pramode C.E Introduction to Functional Programming with Ocaml
Referential Transparency
If an expression can be replaced by its value without changing thebehaviour of the program, it is said to be referentially transparent
All occurrences of the expression 1+(2*3) can be replaced by7 without changing the behaviour of the program.
Say the variable x (in a C program) has initial value 5. It isNOT possible to replace all occurrences of the statement ++xwith the value 6.
Pramode C.E Introduction to Functional Programming with Ocaml
Pure Functions
#include <stdio.h>
int balance = 1000;
int withdraw(int amt)
{
balance = balance - amt;
return balance;
}
int main()
{
printf("%d\n", withdraw(100));
printf("%d\n", withdraw(100));
return 0;
}
Pramode C.E Introduction to Functional Programming with Ocaml
Pure Functions
A pure function always computes the same value given thesame parameters; for example, sin(0) is always 0. It is"Referentially Transparent".
Evaluation of a pure function does not cause any observable"side e�ects" or output - like mutation of global variables oroutput to I/O devices.
Pramode C.E Introduction to Functional Programming with Ocaml
What is Functional Programming?
A style of programming which emphasizes composing your programout of PURE functions and immutable data.
Theoretical foundation based on Alonzo Church's Lambda Calculus
In order for this style to be e�ective in the construction of realworld programs, we make use of most of the ideas seen so far(higher order functions, lexical closures, currying, immutable andpersistent datastructures, lazy evaluation etc)
Pramode C.E Introduction to Functional Programming with Ocaml
What is Functional Programming?
Questions to ask:
Is this the "silver bullet"?
How practical is a program composed completely out of"pure" functions?
What are the bene�ts of writing in a functional style?
Pramode C.E Introduction to Functional Programming with Ocaml
Is FP the silver bullet?
Of course, there are NO silver bullets!(http://en.wikipedia.org/wiki/No_Silver_Bullet)
Writing software is tough - no one methodology or techniqueis going to solve all your problems
Pramode C.E Introduction to Functional Programming with Ocaml
How practical is a program composed completely out ofpure functions?
Very impractical - unless your aim is to �ght the chill byheating up the CPU (which, by the way, is a "side e�ect")
The idea is to write your program in such a way that it has apurely functional core, surrounded by a few "impure" functionsat the outer layers
Pramode C.E Introduction to Functional Programming with Ocaml
Functional core + "impure" outer layers
This example is simple and contrived, but it serves to illustrate theidea. It is taken from the amazing book "Functional Programmingin Scala" by Paul Chiusano and Runar Bjarnason.
let declareWinner p =
let (name, score) = p in
print_string (name ^ "\n")
let winner p1 p2 =
let ((_, score1), (_, score2)) = (p1, p2) in
if (score1 > score2) then (declareWinner p1)
else (declareWinner p2)
Note that "winner" is an impure function. We will now refactor it alittle!
Pramode C.E Introduction to Functional Programming with Ocaml
Functional core + "impure" outer layers
let declareWinner p =
let (name, score) = p in
print_string (name ^ "\n")
let maxScore p1 p2 =
let ((_, score1), (_, score2)) = (p1, p2) in
if (score1 > score2) then p1 else p2
let winner p1 p2 =
declareWinner (maxScore p1 p2)
Now we have separated the computation from the display logic;"maxScore" is a pure function and "winner" is the impure functionat the "outer" layer!
Pramode C.E Introduction to Functional Programming with Ocaml
Bene�ts of functional style - easy reuse, easy testing
What if we wish to �nd out the winner among a set of N players?Easy!
open Core.Std
let maxScore p1 p2 =
let ((_, score1), (_, score2)) = (p1, p2) in
if (score1 > score2) then p1 else p2
let a = [("Ram", 68); ("John", 72); ("Arun", 57)]
let b = List.reduce a maxScore
Pramode C.E Introduction to Functional Programming with Ocaml
FP as "good software engineering"
Pure functions are easy to re-use as they have no "context"other than the function parameters. (Think about re-using the"winner" function in our �rst version to compute the winneramong N players).
Pure functions are also easy to test. (Think about writing anautomated test for the "winner" function in the �rst version).
Think of FP as "Good Software Engineering"!
Pramode C.E Introduction to Functional Programming with Ocaml
Pure functions and the bene�t of "local reasoning"
If your function modi�es an object which is accessible frommany other functions, the e�ect of calling the function is muchmore complex to analyse because you now have to analyse howall these other functions get a�ected by the mutation.
Similarly, if the value computed by your function depends onthe value of an object which can be modi�ed by many otherfunctions, it no longer becomes possible to reason about theworking of the function by only looking at the way thefunction's parameters are manipulated.
The evaluation of pure functions can be done by a very simpleprocess of "substitution".
Pramode C.E Introduction to Functional Programming with Ocaml
Mutability and concurrency
Multi core CPU's are becoming commonplace
We need concurrency in our code to make e�ective use of themany cores
This throws up a whole bunch of complex problems
A function can no longer assume that nobody else is watchingwhen it is happily mutating some data
Pramode C.E Introduction to Functional Programming with Ocaml
Mutability and Concurrency
current_date = [2014, "January", 7]
def changeDate(year, month, day):
current_date[0] = year
current_date[1] = month
current_date[2] = day
def showDate():
print current_date
Pramode C.E Introduction to Functional Programming with Ocaml
Mutability and Concurrency
What happens if the functions changeDate() and showDate() runas two independent threads on two CPU cores? Will showDate()always see a consistent date value?
The traditional approach to maintaining correctness in the contextof multithreading is to use locks - but people who do it in practicewill tell you it is extremely tricky business.
It is claimed that one of the reasons for the resurgence of FP is theemergence of multi-core processors and concurrency - it seems likeFP's emphasis on pure functions and immutability is a good matchfor concurrent programming.
Pramode C.E Introduction to Functional Programming with Ocaml
Moving ahead ...
Prof. Gregor Kiczales "Introduction to Systematic ProgramDesign" is a great online course for beginners:https://www.coursera.org/course/programdesign
Join Prof.Grossman's programming languages class onCoursera: https://www.coursera.org/course/proglangand learn more about functional programming using SML andRacket
Join Prof.Odersky's Functional Programming with Scalacourse on Coursera for an introduction to both Scala and FP:https://www.coursera.org/course/progfun
Watch the classic "SICP" lectures by Abelson and Sussman:http://groups.csail.mit.edu/mac/classes/6.001/
abelson-sussman-lectures/
A talk by Yaron Minsky of Jane Street on how to programe�ectively in ML: http://vimeo.com/14313378
Pramode C.E Introduction to Functional Programming with Ocaml
Books (not limited to Ocaml)
"Ocaml from the very beginning" is a gentle introduction tothe language suitable for beginners:http://ocaml-book.com/
"Real world Ocaml" is the book which will take you to Ocamlmastery: http://realworldocaml.org
SICP, the classic: http://mitpress.mit.edu/sicp/
HTDP: http://www.ccs.neu.edu/home/matthias/HtDP2e/
CTM: http://www.info.ucl.ac.be/~pvr/book.html
Pramode C.E Introduction to Functional Programming with Ocaml
Other resources (not limited to Ocaml)
"Ocaml for the masses" - ACM Queue paper by Yaron Minskyhttp://queue.acm.org/detail.cfm?id=2038036
"Out of the tar pit" - paper by Ben Mosely and Peter Marks(google it)
Lectures by Eric Meijer: google for "C9 Lectures Erik Meijerfunctional"
"Persistent Data Structures and Managed References" - talkby Rich Hickey (author of the Clojure programming language).http://www.infoq.com/presentations/
Value-Identity-State-Rich-Hickey
"Can programming be liberated from the von Neumann style"- by John Backus. http://www.thocp.net/biographies/papers/backus_turingaward_lecture.pdf
Pramode C.E Introduction to Functional Programming with Ocaml