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

Effecting Pure Change - How anything ever gets done in functional programming

Anupam
November 18, 2018

Effecting Pure Change - How anything ever gets done in functional programming

This talk was presented on November 18th 2018 at TechTriveni Conf. (https://techtriveni.com).

Newcomers to functional programming are often mystified when they encounter pure functions and immutable data structures. A mathematical function which always produces the same output for the same input is so inflexible as to be almost useless! And surely how can you even represent even the simplest of dynamic program state without variables to store it in, to say nothing of fancy user interfaces, and complex input output.

This talk will present an overview of the various techniques that are used by functional programming languages to tackle state and external "effects" which are needed for any real world program. It will cover a large landscape ranging from Monads, to Algebraic Effects, to Functional Reactive Programming. And it will show how functional programming can be as *useful* for real world programs, as it is *beautiful*.

Anupam

November 18, 2018
Tweet

More Decks by Anupam

Other Decks in Programming

Transcript

  1. 5 ❑ Programming with Mathematical Functions. ❑ A Function has

    Input and Output. ❑ Referentially Transparent ❑ A complete Program is just a function! Functional Programming
  2. 6 ❑ No Global State ❑ No Assignments ❑ No

    Statements ❑ No Input-Output Referential Transparency
  3. 7 ❑ Easier to Reason About ❑ Easier to Optimize

    ❑ Easier to Parallelize ❑ Easier to Test ❑ ??? Why?
  4. 10 write :: String -> () read :: () ->

    String What could go wrong
  5. 11 write "Do you want a pizza?" if (read() ==

    "Yes") orderPizza() write "Should I launch missiles?" if (read() == "Yes") launchMissiles() What could go wrong PSEUDO-CODE
  6. 12 write "Do you want a pizza?" if (read() ==

    "Yes") orderPizza() write "Should I launch missiles?" if (read() == "Yes") launchMissiles() What could go wrong May be optimized away
  7. 13 write "Do you want a pizza?" if (read() ==

    "Yes") orderPizza() write "Should I launch missiles?" if (read() == "Yes") launchMissiles() What could go wrong May reuse value from previous read()
  8. 14 OCAML let val ha = (print "ha") in ha;

    ha end HASKELL let ha = putStr “ha” in ha >> ha Referential Transparency is Vital ha haha
  9. 16 ❑ Separate “Effects” from “Values” (Hint: Strong Types are

    great for this) ❑ Effects are forever. No way to recover a “pure” Value. ❑ As much as possible, tag the flavor of side effects. “Print” cannot launch nukes. Contain. Not Prohibit.
  10. 18 ❑ React – Functional Views ❑ The Elm Architecture

    ❑ Functional Reactive Programming ❑ Monads and Algebraic Effects Examples
  11. 19 render() { let n = this.state.count return <button onClick

    = {setState({count:n+1})}>{n}</button> } React – Functional Views
  12. 20 view address model = button [onClick address Increment] [text

    (toString model)] update action model = case action of Increment -> model + 1 The Elm Architecture
  13. 21 ❑ Interface between things that are static and those

    that vary ❑ Forms a graph of relationships between varying things ❑ The program creates the graph, and then lets things run. Akin to cellular automata. Functional Reactive Programming
  14. 22 ❑ Event a – e.g. Button Clicks ❑ Behaviour

    a – e.g. System Time ❑ toBehaviour :: Event a -> Behaviour a ❑ mergeEvents :: Event a -> Event a -> Event a ❑ zipBehaviour :: (a -> b -> c) -> Behaviour a -> Behaviour b -> Behaviour c FRP Primitives
  15. 23 ❑ Event a – e.g. Button Clicks ❑ Behaviour

    a – e.g. System Time ❑ hold :: Event a -> Behaviour a ❑ sample :: Behaviour a -> Event b -> Event (a,b) ❑ merge :: Event a -> Event a -> Event a ❑ zip :: Behaviour a -> Behaviour b -> Behaviour (a,b) FRP Primitives
  16. 24 ❑ text :: Behaviour String -> IO () ❑

    button :: Event () ❑ gui = do clicks <- button text hold “Not Clicked” (map (_ -> “Clicked!”) clicks) FRP GUIs
  17. 27 ❑ Values can be evaluated in any order (or

    left unevaluated). ❑ Effects need explicit control over sequencing and sharing. ❑ The only way sequencing is possible in FP is through nested functions. i.e. Callbacks. Controlling Sequencing write "Hello" (() -> write "World")
  18. 28 write "Do you want a pizza?" ( () ->

    read ( ans -> if (ans == "Yes") orderPizza ( () -> write "Should I launch missiles?" ( () -> read ( ans -> if (ans == "Yes") launchNukes () ) ) ) ) ) Continuation Passing Style
  19. 30 () <- write "Do you want a pizza?“ ans

    <- read if(ans == "Yes") () <- orderPizza () <- write "Should I launch missiles?“ ans <- read if (ans == "Yes") () <- launchNukes Sprinkle Some Syntactic Sugar write "Do you want a pizza?" (() -> read (ans -> if (ans == "Yes") orderPizza (() -> write "Should I launch missiles?" (() -> read (ans -> if (ans == "Yes") launchNukes () ) ) ) ) )
  20. 31 do write "Do you want a pizza?“ ans <-

    read if(ans == "Yes") orderPizza write "Should I launch missiles?“ ans <- read if (ans == "Yes") launchNukes Do notation
  21. 32 ❑ Callbacks are generally associated with Asynchronous code ❑

    Do notation avoids “Callback Hell” Asynchronous Computations are Effects ajax GET “google.com" (response -> …)
  22. 33 do post <- ajax GET “/post/1“ map post.comments (\cid

    -> do comment <- ajax GET “/comments/{cid}“ … ) Avoiding Callback Hell ajax GET “/post/1" (post -> map post.comments (\cid -> ajax GET “/comments/{cid}" (comment -> … ) ) )
  23. 36 Type: IO a Bind: IO a -> (a ->

    IO b) -> IO b Return: a -> IO a The Monad
  24. 37 ❑ Reader ❑ Logger ❑ State ❑ Exceptions ❑

    Random ❑ … Bring Your Own Monad
  25. 38 Type: Reader e a :: e -> a Bind:

    Reader e a -> (a -> Reader e b) -> Reader e b Return: a -> Reader e a ask: Reader e e runReader: e -> Reader e a -> a Reader Monad
  26. 39 main = runReader myConfig do res <- foo bar

    res foo = do config <- ask; … bar res = do config <- ask; … Reader Monad
  27. 42 ❑ Like Monads, you can define your own Effects

    ❑ But you can define the usage and handling of the effects separately ❑ And effects compose freely (pun intended) Algebraic Effects
  28. 43 data Console callback = Read (String -> callback) |

    Write String callback handle (Read cb) = … handle (Write s cb) = … Console Effect PSEUDO-CODE
  29. 44 data Console callback = Read (String -> callback) |

    Write String callback handle (Read cb) = s = do readLine(); cb(s) handle (Write s cb) = do console.log(s); cb() Console Effect PSEUDO-CODE
  30. 45 handle (Write s cb) = do console.log(s); console.log(s); cb();

    handle (Write s cb) = cb(); handle (Write s cb) = do cb(); console.log(s); handle (Write s cb) = do if(test(s)) console.log(s); cb(); You can do more things PSEUDO-CODE
  31. 46 handle (Return x) = return (x,””); handle (Write s

    cb) = (x,rest) = do cb(); return (x, s:rest); Returning Values from Handlers PSEUDO-CODE