Functional Programming - Past, Present and Future
-
Upload
pushkar-kulkarni -
Category
Software
-
view
216 -
download
0
Transcript of Functional Programming - Past, Present and Future
Functional ProgrammingPast, Present and
FuturePushkar N Kulkarni
IBM RuntimesIBM India Software Lab
Functional Programming - today’s special …
• Timeline – parallel to the imperative timeline
• Languages• Concepts
Goal: Bootstrapping for functional programming
The beginning of all creation …
Theory of Computation <- Math + Logic
Alonzo ChurchLambda Calculus
Alan TuringTuring Machine
Stephen KleeneRecursive Function
Theory
Lambda Calculus
It’s a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. ~ Wikipedia
Lambda Calculus – Fundamental Idea
x //variable
t //lambda term
Λx.t //lambda abstraction
Λx. x2+1 // x is bound in t by Λx
Λx. x2+1(2) = 22+1 = 5 //application
Note: A lambda abstraction has no name
LISP - 1958
LIST Processor
Influenced by Church’s lambda calculus notation
Multi-paradigm, pre-fix notation
John McCarthy
LISP;;Employee compensation
(defun total (bonus-calc base) (+ (funcall bonus-calc base) base))
;; Good month
(total #'(lambda (x)(* 0.8 x)) 10000)
;; Bad month
(total #'(lambda (x)(+ (* 0.2 x) 10)) 10000)
LISP – Well known dialects
• Scheme – 1970• Common Lisp – 1984• Racket – 1984• Clojure – 2007• Lisp Flavoured Erlang (LFE) – 2008 (v1
March 2016)
Academic Research (1960 – 1985)
• ISWIM – If You See What I Mean – 1966• SASL – St. Andrews Static Language – 1972• ML – MetaLanguage – 1973 => Ocaml, F#• Miranda – 1985 => Haskell
Back to some Lambda Calculus
F(x) = x3+4x //F(x) id a first-order function
//maps values to values
dF(x)/dx = 3x2 + 4
//d/dx maps functions to functions
d/dx is an example of higher-order functions
Higher-order Functions
A function is a higher-order function if:• It takes at least one function as an argument OR• It returns a function
All other functions are first–order functions!
Erlang - 1984
Designed for massive scalable soft real time systems
Fault-tolerance and concurrency
Erlang
Multi-paradigm, but has a functional core•First-class functionsFunctions can be passed to functionsFirst-class citizens=> Higher-order functions•Immutable valuesImmutable “variables” – creating new values insteadMinimizing moving parts has benefits
Erlang – Higher-order functions%base salaries
S = [10000, 30000, 40000, 15000].
%The Bonus calculator
Bonus = fun(X)-> X + X*0.2 + 1500 end.
%Total salaries
T = lists:map(Bonus, S)
>> [13500, 37500, 49500, 19500]
Erlang – Higher-order functions
%find total salaries exceeding 30000
MoreThan30K = fun(Y) -> Y > 30000 end.
lists:filter(MoreThan30K,T).
>> [37500, 49500]
You just learnt “map” and “filter”. Let them sink in!
Haskell - 1990
• Full blown functional language• Algebraic data types and type classes• No statements – the entire program is an
”expression”• Pattern matching• Lazy evaluation• Purely functional – functions have no side effect
Haskell – Algebraic Data Types (ADT)
• Derived from Type Theory• A composite type - formed by combining
other types
data List a = Nil | Cons a (List a)
data Tree a = Node a (Tree a) (Tree a) | Nil
Haskell – Pattern Matching
-- construct a List from an list
makeList (x:xs) = Cons x (makeList xs)
makeList [] = Nil
-- construct an list from a List
makeArr (Cons x (xs)) = x:(makeArr xs)
makeArr Nil = []
Quiz
Why was the language named Haskell?
Haskell Curry (1900 – 1982)
Currying
Introduced by Shönfinkel
Lambda calculus deals with single argument functionsWhat about multiple argument functions then?
If F(X, Y, Z) -> N, then
curry(F): X -> (Y -> (Z -> N))
Lambda Calculus - Currying
F(X, Y, Z) = X + Y + Z
F(1, 2, 3) = Fcurried(1)(2)(3)
//apply only one argument at a time
Fcurried (1) = F’curried
F’curried(2) = F”curried
F”curried(3) = 6
OCaml - 1996
• Multi-paradigm• Derived from ML• Static type system helps eliminate runtime
problems• Emphasis on performance – good
optimizing compiler
Currying in OCaml# let plus x y z = x + y + z;;
# plus 1 2 3;;
- : int = 6
# let x = plus 1;;
val x : int -> int -> int = <fun>
Currying in OCaml# let y = x 2;;
val y : int -> int = <fun>
# y 3;;
- : int = 6
Cool, but what’s the use of all this?
Currying in OCamlFunction to add 2 to all numbers of a listlet add2 x = x + 2
List.map add2 [1;2;3;4;5];;
Function to add 3 to all numbers of a listlet add3 x = x + 3
List.map add3 [1;2;3;4;5];;
Currying in OCaml
With currying:let add x y = x + y
List.map (add 2) [1;2;3;4;5]
List.map (add 3) [1;2;3;4;5]
•Better reuse of code•Improved readability
Quiz
What significant event occurred around 1995 in the Programming
Languages space?
Functional Programming on the JVM
(2004 – date)• Groovy - 2003• Scala - 2004• Clojure - 2007• Java 8 - 2014
Scala
• Seamless integration with Java
• Combines object oriented programming and functional programming
• Type inference• Higher order functions• Pattern matchingMartin
Odersky
Scala
Simple functional code to find the length of a list:(no loops in functional programming!)def listLength (list: List[_]): Int = list match { case Nil => 0 case _ => 1 + listLength(list.tail)}
Any problems here?
Scala
listLength(List.Range(0, 100000))
>> StackOverflow
Are loops better than recursive calls then?Has functional programming hit a barrier here?
Scala - TCONo! You have tail recursion and tail-recursion optimization (TCO)def length(as: List[_]): Int = { @tailrec def length0(as: List[_], count: Int = 0): Int = as match { case Nil => count case head :: tail => length0(tail, count+ 1)
} length0(as)
}
Scala - TCOSimplistic essence of tail-call optimization
Execution state
Single, reusablestack frame
Clojure - 2007Our fascination with LISP is never ending!
Rich Hickey
• LISP for the JVM
• Java-Clojure interoperability
• Other implementations – ClojureScript, ClojureCLR
• Used in creative computing!
Clojure(defn fib[n](condp = n 0 1 1 1 (+ (fib (- n 1)) (fib (- n 2)))))
user=> (time (fib 40))
"Elapsed time: 2946.136757 msecs"
165580141
user=> (time (fib 40))
"Elapsed time: 2882.10746 msecs"
165580141
Clojure
Pure functions•Referential Transparency•No side effects – stateless programs•Given an argument, the function must return the same value! (fib 4) is always 3, for example. => Values (fib K) can be reused for all KSpeed up? Caching?
Clojure - Memoization
(def m-fib(memoize (fn [n] (condp = n
0 1
1 1
(+ (m-fib (- n 1)) (m-fib (- n 2)))))))
Clojure - Memoization
user=> (time (m-fib 40))
"Elapsed time: 0.823773 msecs"
165580141
user=> (time (m-fib 40))
"Elapsed time: 0.082013 msecs"
165580141
Java 8 - 2014
The exciting times begin!•Lambdas•Stream Interface – lazy evaluation!•Functional Interfaces•Default methods – for backward compatibilityA mammoth like Java embracing the functional paradigm is a big cue about the times to come.
Lazy Evaluation
Laziness is not always bad
Lazy Evaluation
• Evaluate an expression only when it’s use is encountered
• Values are created only when needed• Reduction in memory footprint• Fast• In combination with memoization, results in
very efficient functional code
Problem
Find the number of first deliveries of overs, when a batsman who scored at least five centuries and hit at least 100 sixes, was out.
Java 8 – Lazy EvaluationallDeliveries.stream()
.filter(d -> d.deliveryNumber() == 1)
.filter(d -> d.wicket())
.map(d -> d.getBatsman())
.filter(b -> b.totalCenturies() >= 5)
.filter(b -> b.totalSixes >= 100)
.count() //terminal operation
•Lambdas•Immutability•Lazy evaluation, terminal operation•Map/filter
Java 8 - ParallelismParallel execution. Almost zero change to your code.allDeliveries.parallelStream()
.filter(d -> d.deliveryNumber() == 1)
.filter(d -> d.wicket())
.map(d -> d.getBatsman())
.filter(b -> b.totalCenturies() >= 5)
.filter(b -> b.totalSixes >= 100)
.count() //terminal operation
Java 8• No intentions of becoming a full blown
functional language• Lambdas and lazy evaluation provide a big
boost• Readability improved – anonymous classes
not needed• Reusability improved – lambdas, functional
interfaces• Java 9 – better Stream interface expected
Idris – A peek into the future
• Data types are first class objects!• You can generate data types, store them, pass
them around• Dependent types were developed by Haskell
Curry to deepen the connection between programming and logic (Curry-Howard correspondence)
• Dependent types – types that depend on values!• Influenced by Agda
Idris – dependent typesListType : (singleton : Bool) -> Type
ListType False = List Nat
ListType True = Nat
sumList : (singleton : Bool)->ListType singleton->Nat
sumList False (x :: xs) = x + sumList False xs
sumList False [] = 0
sumList True x = x
Why Functional Programming• Higher levels of behavioural abstraction –
tell what is to be done, not how to do it• Agile Methodologies - Code reuse,
readability• Correctness• Exploiting massively parallel hardware
Challenges• Paradigm shift in thinking needed• Newer design patterns – no imperative
design patterns • Performance evaluation difficult – recursive
data structures, recursive functions• Runtime performance – garbage collection
critical
Recap
• Lambda Calculus• Lambdas• First-class functions, higher order functions• Algebraic data types• Pattern matching• Currying
Recap
• Tail-call recursion and TCO• Pure functions, referential transparency• Memoization• Lazy evaluation• Parallelism• Dependent data types
A programming language that does not change the way you think is not worth knowing ~ Alan Perlis
Functional programming changes the way you think.
It’s worth knowing!
(Thank you!)
(twitter @pushkar_nk)(github pushkarnk)