• Save
Introduction to functional programming
Upcoming SlideShare
Loading in...5
×
 

Introduction to functional programming

on

  • 468 views

A brief introduction/summarization on functional programming for Java developers.

A brief introduction/summarization on functional programming for Java developers.

Statistics

Views

Total Views
468
Views on SlideShare
376
Embed Views
92

Actions

Likes
1
Downloads
1
Comments
0

1 Embed 92

http://thangmai.wordpress.com 92

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Introduction to functional programming Introduction to functional programming Presentation Transcript

    • A brief introduction/summarization about functionalprogramming (FP) and paradigm shift of softwareengineering from OOP to FP for Java developersThang Ngoc MaiIntroduction toFunctional ProgrammingKMS Technology
    • 2OOP has served us well but it has drawbacks☐ Hard to Achieve ConcurrencyImperative paradigm does not fit very well with concurrencyneed as it is based on changing state and ordered steps.It is also hard to avoid the evil shared mutability in OOP code.As of now, multithread programming, requiring synchronizedaccess, is the assembly language of concurrency.☐ Less Re-Usable AbstractionsOOP model is hardly usable widely because everyobject model is so unique for eachsituation/problem. This makes modularity of OOPless attractiveAlso it is hard to do it right in OOP design becausethere can be so many candidate models to solve asame problem. And even in case we can make itright, later we still might have to throw them awaywhen business change. And still we can hardly re-use them in other contexts.How many times you have developed theEmployee/Customer classes in your career?It is time to look out for better alternatives.☐ ImperativeIntent of program can be hard tounderstand with imperative codebecause the code is more about howand not about what.
    • 3Why FP?☐ DeclarativeFocus on results, not stepsResult in expressive yet concise code.And thus intent of code is easier tounderstand☐ ConcurrencyThis is the notable reason why FP gainswidespread interest recently.Functions are pure (no side effect) thusare always safe for concurrency. Incontext where mutating state is notavoidable, Actor model and Softwaretransactional memory (STM) come torescue.☐ Coarse-grained AbstractionsFP abstract more details from developers such asiteration/caching/concurrency/lazy evaluation.These mundane details are handled by languages andruntimes, giving developers more time to solve realproblems.The more low-level details a programming languagecan handle for you, the fewer places that leave you tointroduce bugs and complexity.☐ Code Reuse via CompositionFP makes code understandable byminimizing moving parts (changes)A function should be side effect free thushas no dependencies and therefore easierto reuse (better modularity).
    • 4We Should Have FP in Our Toolbox☐ Side EffectsThe biggest advantage of FP and also the biggestdisadvantage of FP is side effect since we do needside effect in software (etc. IO)☐ No PanaceaBoth OOP and FP are tools, not panaceas. Eachhas advantages and disadvantages. Let’s have abigger toolbox and a broadened perspective.
    • 5So What is FP?☐ FP is More a MindsetFP is more a mindset than languages or tools. You can even code functionally in Javaalthough syntax will be cumbersome. First point is when developers think functionally,they should focus on results instead steps to solve a problem.Secondly, because FP represents problems differently with different building blocks,developers have to adapt with these building blocks and how to glue them together.Thus FP requires developers to think in a different way that they do in OOP☐ Programming with FunctionsFunctional program is just a function. Thus functional applications or features are composed bysmall functions together.In OOP, the units of reuse are classes thus it encourages developers to create unique datastructures. In contrast, function is the building block in FP. And thus, FP instead prefers a few keydata structures (list, set, map) with highly optimized operations on those data structures. Thesedifferences are subtle but powerful since it simplify and enable better code reuse mechanism.“Functional programming is a programmingparadigm that treats computation as theevaluation of mathematical functions andavoids state and mutable data”
    • 6Concepts in FPFrom here I will briefly introduce each common concept in functional programming. Below is list of them.Higher Order FunctionFirst Class FunctionCurryingPartial ApplicationMemoizationLazy EvaluationCommon Transformations in FP: filter, map, and reduceDispatch in FPRecursive LoopingMonad
    • 7Higher Order FunctionHigher order functions are functions which can either take other functions as arguments or return them as results.☐ Groovy Exampledef makeCounter() {def very_local_variable = 0return { return very_local_variable += 1 }}c1 = makeCounter()c1()c1()c1()c2 = makeCounter()makeCounter() is a not a normal function. Itis a higher order function which returns aanother function (actually a closure here)which later will be assigned to c1 and c2variables. Note that in Groovy, anythinginside curly braces is a code block.Invoke c1() three times and receive1,2,3 respectively.Invoke makeCounter() again to obtaina new counter function which starts at1
    • 8First Class FunctionFunctional languages treat function as first class citizenWith above definition, you can easily see that function is not (yet) a first class citizen in Java. At least until Java 8 isreleased early next year with support for Lambda Expressions.☐ What is First Class Citizen??☐ What Does All that Mean?First class function allows uses of functions in unexpectedways and force thinking about solutions differently. In OOP,we think about classes and how they are structured andinteract with each other. In FP, we think about functionsand how to create them (even at runtime) and composethem together.In any language, a first class citizen is an entity that canbe: Stored in variables and data structures Constructed at run-time Passed as a parameter Returned from a subroutine Assigned into a variable
    • 9Currying Currying is a technique of transforming afunction that takes multiple arguments in sucha way that it can be called as a chain offunctions, each with a single argument.☐ How Does It look?Given , currying produces:.☐ JRuby Examplesproduct = ->(x,y,z){x * y * z}product.(2,4,6)product.curry[2][4][6]We create a lambda here (assigned to product) whichtake three parameters and multiple them together andreturn resultproduct can be invoked either in anormal way or in a curried way likethis to produce a same result of 48product = ->(x,y){x * y}double = product.curry[2]quadrate = product.curry[4]octate = product.curry[8]Again, create a lambdaBut this time, we use currying to createthree different functions based on originalone. This demonstrates idea about curryingacts as a factory for functions
    • 10Partial Application☐ DefinitionPartial application (or partial function application) refers to the process of fixing a number ofarguments to a function, producing another function of smaller arity.Note that partial application is different with currying but these two terms are often usedinterchangeably☐ JRuby Examplebinary_operator = ->(operator, x, y){operator[x,y]}adder = ->(x,y){x + y}product = ->(x,y){x * y}# Use curry() for partial applicationcurried_product = binary_operator.curry[product]curried_adder = binary_operator.curry[adder]# Note Ruby’s beautiful syntaxcurried_product1 = binary_operator.curry[:*]curried_adder1 = binary_operator.curry[:+]# returns 30curried_product.(5,6)# returns 11curried_adder.(5,6)binary_operator is a higher orderfunction which take a binary functionand apply it to the other parameters.We have two binary operatorsadder and product.We use curry in JRuby to partiallyapply adder and product tobinary_operator function and yieldingtwo functions.
    • 11Partial Application☐ Another Examplecomposer = ->(f,g,x){f.(g.(x))}product = ->(x,y){x * y}double = product.curry[2]quadrate = product.curry[4]octate = composer.curry[double, quadrate]# Returns 800octate.(100)We define a function to combinefunctions together.Then use partial application to yield a newfunction from two original ones.
    • 12OOP Design Patterns in FPNeal Ford has three articles on this topic. According to those, in the functional-programming world, traditional designpatterns generally manifest in one of three ways:The pattern is absorbed by the language.The pattern solution still exists in the functional paradigm, but the implementation details differ.The solution is implemented using capabilities other languages or paradigms lack. (For example, many solutionsthat use metaprogramming are clean and elegant — and theyre not possible in Java.)I just try to summarize his articles here into a few points below.Command pattern is no longer needed in FPCurrying is used as Function Factory and it is supported at language levelWith first class function, Template Method and Strategy, Adapter become much simplerWith presence of memorization (Groovy and Clojure), FlyWeight is not necessary any more. This is an example ofoffloading mundane tasks to language and runtimesOperator overloading and meta-programming makes Interpreter become much simpler and more powerfulLanguage level feature like Pattern matching in Scala make Visitor pattern cumbersome and almost no longerneeded (Martin et al. chapter 15).
    • 13Caching and MemoizationIn OOP languages, caching generally happen at object level and developers mush manage it themselves. Many functionalprogramming languages build caching in function level via memorization. This is also an example of how FP strives tominimize moving parts by building reusable mechanism into the runtime. Again the idea is all about buying more time fordevelopers to focus on their own tasks. Memorization is all about asking runtime to perform caching at function level(Note that a non-pure function should not be cached as it is a source of bugs). Let’s take a look at a sample API formemorization from Groovy to see how handy they are.memoizeAtMost(max) call which caches a maximum number of invocationsmemoizeAtLeast(min) call which keeps at least a certain number of invocation resultsand memoizeBetween(min, max) which keeps a range results (between a minimum and a maximum)def plus = { a, b -> sleep 1000; a + b }.memoize()assert plus(1, 2) == 3 // after 1000msassert plus(1, 2) == 3 // return immediatelyassert plus(2, 2) == 4 // after 1000msassert plus(2, 2) == 4 // return immediately// other forms://at least 10 invocations cacheddef plusAtLeast = { ... }.memoizeAtLeast(10)// at most 10 invocations cacheddef plusAtMost = { ... }.memoizeAtMost(10)// between 10 and 20 invocations cacheddef plusAtLeast = { ... }.memoizeBetween(10, 20)
    • 14Lazy Evaluation☐ What is It?Lazy evaluation is deferral of expressionevaluation for as long as possibleIt is a feature of many functionalprogramming languages☐ Why Lazy Evaluation matter? Defer expensive calculation until they areabsolutely needed Can create infinite collections which is notpossible with eager collections Reduced storage size as we don’t have to storeeverything upfront Allow to generate more efficient code
    • 15Common TransformationsObject-oriented languages encourage us to create class-specific methods, and you can capture recurring patterns for later reuse. Functionallanguages help us to achieve reuse by encouraging the application of common transformations to data structures, with higher-order functions tocustomize the operation for specific instances. Below are common transformations in FP which have different names in different languages. Notethat there are inconsistencies of terminology for same transformation in different languages. Here I summarize some common transformationswhich are well noted in article #16 in Neal Ford’s functional thinking series.☐ map and collectA transformation which invokes a function on eachelement from a list then creates a new list containingvalues return by that function☐ filter & findAll &selectA transformation which invokes an input predicate oneach element from a list to determine which values willbe included in the return list.A predicate is a function which only returns true orfalse.☐ Reduce & inject & reduceLeftCombine all elements by applying a specified binaryoperation
    • 16Map & Collect# Returns result: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20](1..10).map{|x| x * 2}# Returns result: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20](1..10).collect{|x| x * 2}def list = 1..5// return result: [10, 20, 30, 40, 50]list.collect {10 * it}☐ JRuby ☐ Groovyval list = 1 until 5//Return result: Vector(10, 20, 30, 40)l.map(x => x * 10); Returns result: (10 20 30 40 50 60 70 80 90)(map #(* 10 %) (range 1 10))☐ Clojure☐ Scala
    • 17Filter & findAll & select# Returns result: [2, 4, 6, 8, 10](1..10).select{|x| x % 2 ==0}def list = 1..10// Return result: [2, 4, 6, 8, 10]list.findAll {it % 2 == 0}☐ JRuby☐ Groovyval list = 1 until 5//Return result: Vector(2, 4)list.filter(x => x%2 == 0); Returns result: (2 4 6 8)(filter #(= (mod % 2) 0) (range 1 10))☐ Clojure ☐ Scala
    • 18Reduce & inject & reduceLeft# Returns result: 55(1..10).reduce(:+)def list = 1..10// return result: 55list.inject {x,y -> x + y}☐ JRuby ☐ Groovyval list = 1 until 11//Return result: 55list.reduceLeft((a,b) => a + b); Returns result: 55(reduce + (range 1 11))☐ Clojure☐ Scala
    • 19pmap in ClojureAs we are familiar with map already in previous page, lets examine pmap (paralel) in Clojure which will execute mappingsconcurrently (and also semi-lazily). Presence of building block such as pmap demonstrates idea (yes, again) how languageand runtimes can handle mundane tasks for developers so that we will have more time to focus on resolving realproblems.I left out implementation of fetch-url since it is not needed to demonstrate the idea. Let’s suppose we already had fetch-url function implemented somewhere. The code in this example executes fetching content from each website in parallel.If you are already familiar with Execution Framework in Java (I assume you are) then you can see that how cumbersome itis the equivalent code in Java to do the same thing here with all Callable, Future, Executor, ExecutorService along the way.Let language and runtimes do these things for us. Here I want to mention a quote from Dean Wampler:“Multithreaded programming, requiring synchronized access to shared, mutable state, isthe assembly language of concurrency”; Having a list of url to fetch(def url-list (list "www.url1.com" "www.url2.com" "www.url3.com")); Returns(pmap #(fetch-url %) url-list)☐ pmap Contrived Simple Stupid Example
    • 20Parallel Collections in ScalaThanks to Nhan Tran who gave me an example about parallel collections in Scala which is similar to the pmap exampleabove in Clojure but with different approach. Instead of concurrent function, concurrency is built inside parallelcollections like ParArray, ParVector, ParHashMap etc. Let’s take a look at an example.Above example is from scala’s documentation on parallel collections in following link.http://docs.scala-lang.org/overviews/parallel-collections/overview.html// Create a listval list = (1 to 10000).toList// Convert it to a parallel list with par() then call map to transform to// a new list by adding 42 to each element concurrently.list.par.map(_ + 42)
    • 21Dispatch in FPWorking on Java, we depend on if and switch statements for dispatch. FP provides us some alternatives for the samepurpose. Groovy offers a switch statement which accepts dynamic types while Scala’s flavor is pattern matching. AndClojure has multi methods – a functional polymorphism which is equivalent to polymorphism in OOP with fewerlimitations. Let’s take a look.☐ Multi Methods Example(defmulti auto-answer (fn [caller] (caller :is-a)))(defmethod auto-answer :girl [caller] "I love you")(defmethod auto-answer :friend [caller] "Whats up")(defmethod auto-answer :colleague [caller] "How are you")(defmethod auto-answer :boss [caller] "Yes sir, sure")(defmethod auto-answer :default [caller] "mmm")=> (auto-answer {:is-a :friend})"Whats up"=> (auto-answer {:is-a :colleague})"How are you"=> (auto-answer {:is-a :girl})"I Love You"In Clojure, a dispatch function isdefined by defmuti. Anyinvocation of auto-answer willpass parameters to this function.Based on value retuned bydispatch function, execution willbe dispatched to appropriatemethod. This is similar withbehavior we have in OOP’spolymorphismAll these new dispatch mechanisms arepowerful and we don’t need to depend ondesign patterns like Factory but theyrequires a change in the way we think as itis part of thinking functionally
    • 22Recursive LoopingAt this point, you might not be surprised any more to know that functional approach does not favor use ofconstructs like ‘for’ and ‘while’ for looping and iteration. Instead, Looping and iteration are replaced /implemented by recursive function calls (Rich Hickey)☐ What Languages Support Tail Recursion?Clojure has ‘recur’ and trampoline’ as special operators to support tail call optimization(TCO).Scala support tail call optimization at language level.Groovy does not (yet) support TCO. However it has trampoline.JRuby does not support TCO yet.Tail call and tail recursion is a subproject to introduce TCO for the JVM and Hopefully JDK 1.8will come with TCO support. That would enable TCO for all languages on the JVM.☐ So What about Stack Space Problem?Recursion is nice but it has a problem with stack space consumption. Recursive function can easilyresult in a stack overflow exception with large enough recursive calls.Many languages guarantee that function calls made in tail position do not consume stack space andthus recursive loops utilize constant space. Note: Same optimization cannot be achieved with headrecursion.With such tail recursion optimization, we have peace in mind when writing recursive function.
    • 23MonadProbably Monad is the most difficult to understand concept in functional programming. It could take you 3 days orprobably months to understand. However, the good news is you don’t need to understand Monad to apply FP in yourdaily assignments. Once you get used to functional programming, I believe soon you will understand Monad. I wouldrecommend following articles for getting started:Understanding monadshttp://en.wikibooks.org/w/index.php?title=Haskell/Understanding_monads&oldid=933545Don’t fear monadshttp://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-MonadsIn case you need more articles, here is a consolidated list of all tutorials about monadshttp://www.haskell.org/haskellwiki/Monad_tutorials_timeline
    • 24FP is On The Rise☐ Results over StepsJava eased our interaction with memorymanagement; functional programming languageseased our focus on how steps should be done.Examples are details on concurrency, iteration,transformations and caching can be handled bylanguages and runtime.The more low-level details a programming languagecan handle for you, the fewer places that leave youto introduce bugs and complexity☐ Think FunctionallyFP offers new and powerful tools which can help solve tricky problems inelegant ways. Developers need to adapt to functional thinking to make useof them effectively.So start thinking about resolving problem with how, wrapping function inlist/tree/hash, manipulating array and tree with functions and so on.☐ Minimize Moving PartsOOP makes code understandable byencapsulating moving parts. FP makes codemore understandable by minimizingmoving parts. Immutability is one primaryreason why FP shines in concurrency.
    • 25Recommendation on Where to Start1. If you are a Java developer and you are new to FP then first go through 20 articles from Neal Ford in his functionalthinking series. These series of articles would have convinced you on how elegant and powerful FP is. I like NealFord’s series because it discuss in detail on how FP can help us (developers) to work more efficiently. The series isalso very readable.2. Then, you might want to start with the book “Functional Java Programming for Java Developers” to have a fair gripon Data structures / Algorithm / Concurrency in FP.3. You then can start to learn and use a functional language seriously like Scala or Groovy or Clojure. I was startedwith Clojure (and Clojure is my favorite) but I would recommend Scala or Groovy as I think getting familiar toClojure syntax could distract your focus on FP concepts.4. From that point, you might want to tackle the most difficult topic in FP: Monad. Notes: You should not start tolearn FP with Monads. That would slow your learning process.
    • 26References1. Functional Thinking 20 articles series – Neal Ford - http://www.ibm.com/developerworks/java/library/j-ft1/index.html2. Dean Wampler 2011. Functional Java Programming for Java Developers3. Why Functional Programming Matters - http://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf4. Object Oriented Programming Oversold - http://www.geocities.com/tablizer/oopbad.htm5. Martin, F., 2010. Domain Specific Languages. Addison Wesley6. Venkat, S., 2011. Programming Concurrency on the JVM7. Functional Programming - http://en.wikipedia.org/wiki/Functional_programming8. Don’t fear monads: http://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads9. State of Lambda: Libraries Edition: http://cr.openjdk.java.net/~briangoetz/lambda/collections-overview.html10.Martin at el. 2011. Programming in Scala 2nd edition. Artima Inc;