Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Functional Programming in Anger (Basics)

Norman
April 04, 2019

Functional Programming in Anger (Basics)

Introduction to pragmatic functional programming for object-oriented developers. Using PureScript as example.

Norman

April 04, 2019
Tweet

More Decks by Norman

Other Decks in Programming

Transcript

  1. F U N C T I O N A L

    P R O G R A M M I N G I N A N G E R R E C O N C I L I N G F P A N D O O PAT T E R N S Norman Thomas 04 Apr 2019
  2. S H O RT N OT E S • Ask

    questions right away, at any time • Code examples are pseudo-code but very close to the real deal • I promised FP, but will talk a whole lot about OOP FP = functional programming OO = object-oriented / object-orientation OOP = object-oriented programming OOPL = object-oriented programming language OODP = object-oriented design pattern !2
  3. OV E RV I E W • Motivation • Claims

    • Patterns • Outlook !3
  4. H I STO R Y • Halting Problem / “Entscheidungsproblem”

    • Lambda Calculus (Apr 1936) • Turing Machine (May 1936) • First FP language LISP (1950s) • First OOP language Simula (1960s) !4
  5. F U N C T I O N A L

    P R O G R A M M I N G : W H Y N O W ? • CPU clock speeds plateaued • CPUs these days increase number of cores • Shared mutable state does not scale well in multi-core/node systems
 requires lock / mutex / semaphore • Extensive experience with other paradigms • Strong desire to kill spaghetti monsters !5
  6. T H E F U N N Y S L

    I D E C++ An octopus made by nailing extra legs onto a dog. Java C++ with all the knives, guns, and clubs put away. JavaScript Any application that can be written in JS will eventually be written in JS. Perl There is more than one way to do it. Python Compile, run and ship your pseudo-code. There should be one — and preferably only one — obvious way to do it. !6
  7. A N OT H E R F U N N

    Y S L I D E Erlang Let it crash. Compile once run forever. Lisp To iterate is human; to recurse is divine. Haskell Avoid “success at all costs”. If it compiles, it probably works. We cannot afford QA teams, so we use a sadistic compiler. An hour of meditation, followed by the emission of a single 'fold' expression. !7
  8. W H AT D O W E WA N T

    ? • Organised, well structured code • Code reuse • Understandable code • Scalable, adaptable code • Write less code, achieve more !9
  9. PA R A D I G M S !10 i

    m p e rat i v e d e c l a ra t i v e o b j e c t - o r i e n t e d f u n c t i o n a l p ro c e d u ra l l o g i c
  10. O O C L A I M S / P

    R O P E RT I E S • Three pillars of OOP • Encapsulation • Inheritance • Polymorphism !12
  11. O O C L A I M S : E

    N CA P S U L AT I O N • OO actually reduces encapsulation • Public *.hh/hpp header file contains implementation details • Change of private members triggers rebuild • member variables introduce state and therefore dependency on time/ order of invocations • encapsulation ≠ namespacing !13
  12. OO did not give us encapsulation, OO weakened encapsulation. …It

    destroyed good encapsulation… Robert C. Martin “Uncle Bob”
  13. O O C L A I M S : I

    N H E R I TA N C E • Promises code reuse • Code reuse also achievable by composition • Base and child class are tightly coupled • Composition encouraged over inheritance !15
  14. Ideally, you shouldn't have to create new components to achieve

    reuse. You should be able to get all the functionality you need just by assembling existing components through object composition. Design Patterns: Elements of Reusable Object-Oriented Software, p. 20
  15. The problem with object-oriented languages is they’ve got all this

    implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. Joe Armstrong about OOP reality, not the original idea
  16. O O C L A I M S : P

    O LY M O R P H I S M • Rely on abstract interface (method signatures) • Runtime depends on instanciated subclass • Allows dependency injection • Fundamental core idea of OOP !18
  17. S O L I D P R I N C

    I P L E S • Single responsibility principle • Open/close principle • Liskov substitution principle • Interface segregation principle • Dependency inversion principle !19
  18. I’m sorry that I long ago coined the term “objects”

    for this topic because it gets many people to focus on the lesser idea. The big idea is messaging. Alan Kay about OOP
  19. OOP to me means only messaging, local retention and protection

    and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. Alan Kay about OOP Actually I made up the term “object-oriented,” and I can tell you I did not have C++ in mind.
  20. I N T E N T I O N B

    E H I N D O O • Messaging between entities as core principle • More reliable function pointers and dynamic dispatch • Objective-C closer to Alan Kay’s definition of OO than C++ !22
  21. H O W O F T E N D O

    YO U U S E P O LY M O R P H I S M ? Q U E S T I O N :
  22. F P C L A I M S • Reusable

    code through composition • Mathematically sound principles/patterns • Declarative style boost algorithm readability • Increases modularity, functions typically do one thing only • Simplifies local reasoning about behavior !24
  23. F P P R O B L E M S

    • Higher barrier of entry, because looks alien • less wide-spread, but gaining momentum • bias towards OOP • we’re taught OOP and OODP at university and almost everywhere else • reputation of being mathematical / difficult • unfamiliar terminology
 These didn’t come to us naturally either:
 Inheritance, Interface, Polymorphism, Generics, SOLID, Abstract Class, Inversion of Control, method/member/static,
 GoF Patterns, or even mutable state management lock/mutex/semaphore, … !25 λx . x
  24. OV E RV I E W O F O O

    P A N D F P
  25. D E F I N I T I O N

    • There is no “the OOP” or “the FP” • Various nuances exist • Static vs dynamic typing has major impact • OOP and FP are not mutually exclusive !27
  26. M I N I M A L D E F

    I N I T I O N S • OO • Polymorphism • Message passing • FP • Evaluation of expressions • First-class functions (→ lean function composition) !28
  27. OT H E R F P P R O P

    E RT I E S Depending on language • Purity • Immutability • Referential transparency • Lazy evaluation • Memoization • TDD (Type-Driven Development) !29
  28. VA R I O U S N UA N C

    E S O F O O • C++ • Separate header and implementation files • Header files still polluted with implementation details, i.e. private members / methods • Freedom to use or not use classes • Java • Everything is an object • No separation between implementation and header files, except for interfaces • Python • No separation between interface and implementation, except maybe abstract base classes • Duck typing: no inheritance necessary to conform to an interface • JavaScript, etc. !30
  29. N UA N C E S O F F P

    Lisp, Scheme, Clojure, CLJS • impure • dynamically typed • interpreted
 Haskell, PureScript, Elm, Agda, Idris • pure • statically typed • compiled Erlang, Elixir • impure • dynamically typed • compiled F# • impure • statically typed !31
  30. Q U E ST I O N Do you know

    the difference between the following patterns? • Adapter Pattern • Bridge Pattern • Decorator Pattern • Delegation Pattern • Façade Pattern • Proxy Pattern !33 converts one interface to another to match what client is expecting decouples implementation from abstraction to permit independent variation dynamically wraps original implementation with more functionality delegates call to another object provides a simplified interface helps control access to a resource (e.g. connection, caching)
  31. A F E W M O R E O O

    PAT T E R N S • Abstract Factory Pattern • Command Pattern • Composite Pattern • Factory Method Pattern • Iterator Pattern • Observer Pattern • Singleton Pattern • Visitor Pattern !34 *we’ll come back to the bold patterns later
  32. F U N C T I O N A L

    PAT T E R N S FA M I L I A R
  33. U N S U S P E C T I

    N G F P E L E M E N T S • Promises / Futures • Optional / std::optional • Arrays, Lists • Function pointers / lambda functions / std::function • Higher order functions / map, filter, reduce / std::transform, std::copy_if, std::accumulate • Immutability / const • Ternary operator / … if … else … / … ? … : … • const functions • Partial application / std::bind !36
  34. H AV E YO U E V E R WO

    N D E R E D… • why an array / vector / list is so useful and universal? • why working with promises or async/await is so much more delightful than with callbacks? • why one of the below function signatures is more expressive? void f(string a, int &b); int f(string a); !37
  35. I M M U TA B I L I TY

    • Ensures that a variable’s value won’t change • Prohibits accidental change of value • Thread safety • Makes reasoning about code easier • Simpler debugging !38
  36. L A M B DA F U N C T

    I O N S / F U N C T I O N P O I N T E R S • Creation of ad-hoc functions to inject behavior • e.g. sort function with injectable sorting criteria • Reduces amount of code • Can improve readability !39
  37. O P T I O N A L • Omnipresent

    null is evil and dangerous • Optionals allow handling “null” in more explicit way • In FP optional (maybe) reduces amount of if-else branches like: • if (ptr == NULL) • if obj is None • if (obj === undefined) • Swift has a very intuitive syntax: obj?.do_something() !40
  38. P R O M I S E S / F

    U T U R E S / A SY N C • Perform some computation • Computation eventually yields a value, or an error • Can be chained !41 Promises, Futures, Async are Monads!
  39. P U R E S C R I P T

    * Q U I C K- D I V E A L I T T L E B I T O F S Y N TA X *very similar to Haskell
  40. W H Y P U R E S C R

    I P T ? • Pure and strict functional language • Can’t fall back to using imperative/OOP patterns • Statically typed, powerful type system • Terse, expressive syntax • Multiple backends, compiles to:
 JavaScript, C++ 11, Erlang, C, Python, … !43
  41. SY N TA X : F U N C T

    I O N A P P L I CAT I O N • C, C++, Java f(x); • Python, JavaScript f(x) • Lisp, Clojure (f x) • Haskell, PureScript, ML f x !44
  42. SY N TA X : F U N C T

    I O N D E F I N I T I O N • C++, Java int add(int a, int b) { return a + b; } • Python def add(a: int, b: int) -> int: return a + b • TypeScript, JavaScript const add = (a: number, b: number): number => a + b; • PureScript, Haskell add :: Int -> Int -> Int add a b = a + b !45
  43. SY N TA X : TY P E D E

    F I N I T I O N S • PureScript type Model = String newtype Make = Make String data Car = Car { make :: Make model :: Model }
 type Name = String data Gender = M | F | D data Human = Human Name Gender data Person = Person { self :: Human mother :: Person father :: Person children :: Array Person } !46
  44. SY N TA X : S W E E T,

    S W E E T S U G A R • Python def getAllDocumentEANs() -> List[str]: result = [] for d in [186, 196, 1387]: for p in ["epub", "pdf", "mobi", "pod", "audiobook", "software"]: result.append(getEAN(d, p)) return result • PureScript newtype EAN = EAN String getAllDocumentEANs :: Array EAN getAllDocumentEANs = do d <- [186, 196, 1387] p <- ["epub", "pdf", "mobi", "pod", "audiobook", "software"] [getEAN d p] !47
  45. CO M PA R A B L E : P

    U R E S C R I P T -- | Sum type: distant, more powerful cousin of a C union or enum data Ordering = EQUAL | LOWER | GREATER -- | Type Class: akin to Java interfaces or C++ abstract class class Comparable a where compare :: a -> a -> Ordering -- | Custom type declaration data Human = Human Int -- | Implement a class that fulfills the above type class / interface instance compareHuman :: Comparable Human where compare :: Human -> Human -> Ordering compare (Human age1) (Human age2) | age1 == age2 = EQUAL compare (Human age1) (Human age2) | age1 > age2 = GREATER compare (Human age1) (Human age2) | age1 < age2 = LOWER !48
  46. CO M PA R A B L E : C

    + + enum Ordering { LOWER, EQUAL, GREATER }; class Comparable { public: virtual Ordering compare(const Comparable &other) const = 0; }; class Human : public Comparable { private: int age; public: Human(const int age); Ordering compare(const Human &other) const override; }; Human::Human(const int age) { this->age = age; } Ordering Human::compare(const Human &other) const { if (this->age == other->age) return EQUAL; if (this->age > other->age) return GREATER; return LOWER; } !49
  47. F U N C T I O N A L

    PAT T E R N S A P P L I E D
  48. O P T I O N A L / M

    AY B E • Does this kind of code look familiar? # Python def get_user_country(user: Optional[User]) -> Optional[str]: if user is not None: address = user.get("address") if address: return address.get("country") return None —- | PureScript / Haskell get_user_country_v1 :: Maybe User -> Maybe String get_user_country_v1 user = user >>= get "address" >>= get "country" get_user_country_v2 :: forall m. Monad m => m User -> m String get_user_country_v2 user = user >>= get "address" >>= get "country" !51 # Python / EAFP def get_user_country(user): try: address = user.get("address") return address.get("country") except AttributeError: return None
  49. E I T H E R • How many times

    have you written/seen code like this: # Python def _check_suitability(self, isbn: str, distributable: bool) -> Tuple[bool, str]: if isbn is None: return False, 'no-isbn' if not distributable: return False, 'publication-is-not-distributable' return True, '' —- | PureScript / Haskell check_suitability :: Maybe ISBN -> Distributable -> Either String Unit check_suitability Nothing _ = Left "no-isbn" check_suitability _ False = Left "publication-is-not-distributable" check_suitability (Just isbn) _ = Right unit !52
  50. A SY N C • Python async def request(url: str)

    -> str: async with aiohttp.ClientSession() as session: resp = await session.get(url) as resp if resp.status == 200: resp2 = await session.get(await resp.text()) as resp2 return await resp2.text() async def main(): return await request("http://grin.to/pointme") asyncio.run(main()) • PureScript request :: URL -> Aff String request url = do resp <- Ajax.get url resp2 <- Ajax.get resp.body pure resp2.body main = launchAff $ request "http://grin.to/pointme" !53
  51. A R C H I T E C T U

    R E S W I T H F U N C T I O N A L E L E M E N T S • Frameworks, e.g. Spark, Flink, Storm, Samza • Data transformation without mutation (immutability) • Declarative • Higher order functions + function composition • Databases / data storage, e.g. Kafka, TimescaleDB • Append only (immutability) • Infrastructure as Code • Immutability • Same input (config) yields same output (infrastructure) !54 Toward a Functional Programming Analogy for Microservices
  52. M ATC H I N G PAT T E R

    N S F R O M O O T O F P A N D B A C K
  53. P O LY M O R P H I S

    M • In OO classes implement an interface or inherit from another class
 (subclass polymorphism) • In OO classes can implement multiple interfaces, inherit from one or multiple classes, depending on language • In statically typed FP, free functions are implemented to fulfill an interface (a type class) • In FP a type can follow multiple interfaces (type classes) • FP introduced parametric polymorphism • In dynamically types languages, duck typing replaces inheritance-based polymorphism !56
  54. P O LY M O R P H I S

    M public interface Iterable<T> { public void append(T value); public T next(); public boolean hasNext(); } public class MyCollection<T> implements Iterable<T> { private Array<T> arr; private int index; public MyCollection() { this.arr = new Array<T>(); } public void append(T value) { this.arr.add(value); } public T next() { return this.arr[this.index++]; } public boolean hasNext() { return this.arr.length > this.index; } }
 class Iterable f where hasNext :: ∀ a. f a -> Int -> Boolean next :: ∀ a. f a -> Int -> Maybe a append :: ∀ a. f a -> a -> f a newtype MyCollection a = MyCollection Array a instance myCollectionIterable :: Iterable MyCollection where hasNext :: ∀ a. MyCollection a -> Int -> Boolean hasNext coll pos = (length coll) > pos next :: ∀ a. MyCollection a -> Int -> Maybe a next coll pos | (length coll) <= pos = Just (coll !! pos) next _ _ = Nothing append :: ∀ a. MyCollection a -> a -> MyCollection a append coll el = coll <> [el] !57
  55. FAC TO R Y PAT T E R N S

    • Purpose is inversion of dependency • In OOP • Create class hierarchy • Implement subclasses • Function depends on base class, but will pass a subclass instance when calling • In FP • Implementation dependency: inject function as argument • Data structure dependency: parametric polymorphism !58
  56. I T E R ATO R PAT T E R

    N • A way of walking through a data structure and accessing its elements • In FP • Iterable type class • Traversable type class • Functor! !59
  57. CO M M A N D PAT T E R

    N • Encapsulate/describe commands without executing them right away • In most OOPL • Build an abstract class / interface with an abstract method • Pass in implemented subclass of which the method will later be invoked • In FP • Pass function as parameter and execute it later !60
  58. S U M M A R Y M A I

    N TA K E - A WAY S
  59. O O P A N D F P A R

    E N OT E N E M I E S
  60. O U T LO O K • Lisp, Haskell, Erlang

    and other FP languages frequently serve as source of inspiration for other languages and libraries
 e.g. C++, Akka, JavaScript, Ramda.js, Python, … • Haskell’s motto is avoiding “success at all costs”,
 i.e. don’t give in to comfort by sacrificing expressiveness/safety/efficiency • Embrace FP concepts/patterns that can help day-to-day work
 immutability, purity, referential transparency, abstraction, composition • Libraries to help apply functional style exist, e.g.
 Python: pyrsistent, OSlash, toolz, pyfunctional
 JS: immutable.js, lodash, ramda, sanctuary, fluture
 C++: FunctionalPlus !63
  61. W H AT I T B O I L S

    D O W N TO • Don’t take concepts at face value • Challenge yourself, stay adaptable • Awareness, consciousness, take a step back and get a new perspective • Continuous improvement • Look beyond horizon
 Learning new concepts helps finding new perspectives in existing ones !64 Assess advertised properties, as you would do for frameworks, etc. Question your solution and try to find a better one Trying different angles to solve a task Through learning, refactoring 
 Like learning a new language improves understanding of mother tongue
  62. R E S O U R C E S •

    Follow-up presentation by me about more advanced FP concepts
 if there’s demand • PureScript Documentation • Haskell Documentation • Haskell Programming from First Principles • PureScript by Example !65
  63. L I N K S • Robert C. Martin: SOLID

    Principles of Object-Oriented and Agile Design • Robert C. Martin: Functional Programming — What? Why? When? • CppCon 2017 Klaus Iglberger: Free Your Functions • GoingNative 2013 Sean Parent: C++ Seasoning (no raw loops) • Dr. Erik Meijer: Functional Programming Fundamentals Lectures ☮ • Scott Wlaschin: Functional Design Patterns • Introduction to PureScript & • Functional Programming Jargon • Functional Programming Concepts • Toward a Functional Programming Analogy for Microservices • Fantasy-Land !66
  64. YO U ’ V E B E E N A

    G R E AT AU D I E N C E